Development of "Name Your Price" functionality on 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
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1175
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Website development for FIXPER company
    811
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Development based on Bitrix, Bitrix24, 1C for the company Development of an Online Appointment Booking Widget for a Medical Center
    564
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Development based on 1C Enterprise for MIRSANBEL
    747
  • image_crm_dolbimby_434_0.webp
    Website development on CRM Bitrix24 for DOLBIMBY
    655
  • image_crm_technotorgcomplex_453_0.webp
    Development based on Bitrix24 for the company TECHNOTORGKOMPLEKS
    976

Developing "Name Your Price" Functionality for 1C-Bitrix

The PWYW (Pay What You Want) mechanism allows a customer to enter their own amount for goods or a service — with a possible minimum threshold. Bitrix doesn't support this out of the box: the price in b_catalog_price is fixed, and the sale module doesn't accept arbitrary amounts from clients. All logic is overridden at the cart and checkout level.

Where to Store Settings

For each product participating in the mechanism, three additional parameters are needed:

  • PWYW_ENABLED — active flag (Y/N)
  • PWYW_MIN_PRICE — minimum amount (can be 0)
  • PWYW_SUGGESTED_PRICE — suggested amount (displayed by default)

Storage — infoblock properties of the catalog. For SKUs (trade offers), they are added via CIBlockProperty::Add() to the IBLOCK_ID of trade offers. Property types — N (number) for prices, S for flag.

Alternative — HL block PwywSettings with fields UF_PRODUCT_ID, UF_MIN_PRICE, UF_SUGGESTED_PRICE, UF_ACTIVE. Suitable when you need to manage settings in bulk from admin interface without editing each product.

Intercepting Price on Cart Add

Standard $basket->addItem() takes price from the catalog. Need to intercept before saving and substitute the client's price.

Client side: form on product page contains pwyw_price field. On submit — AJAX to custom endpoint.

Server handling:

use Bitrix\Sale\Basket;
use Bitrix\Sale\BasketItem;
use Bitrix\Main\Context;

$request = Context::getCurrent()->getRequest();
$productId = (int)$request->getPost('product_id');
$userPrice = (float)$request->getPost('pwyw_price');

// Check minimum threshold
$minPrice = getPwywMinPrice($productId); // reads infoblock property
if ($userPrice < $minPrice) {
    echo json_encode(['error' => 'Price below minimum']);
    die();
}

$basket = Basket::loadItemsForFUser(
    \CSaleBasket::GetBasketUserID(),
    \Bitrix\Main\Context::getCurrent()->getSite()
);

$item = $basket->createItem('catalog', $productId);
$item->setFields([
    'QUANTITY'           => 1,
    'CURRENCY'           => \Bitrix\Currency\CurrencyManager::getBaseCurrency(),
    'LID'                => SITE_ID,
    'PRODUCT_PROVIDER_CLASS' => 'CCatalogProductProvider',
    'PRICE'              => $userPrice,
    'BASE_PRICE'         => $userPrice,
    'CUSTOM_PRICE'       => 'Y',  // prevent auto-recalculation
]);

// Save entered price in basket property
$item->getPropertyCollection()->setProperty([
    'NAME'  => 'PWYW_PRICE',
    'CODE'  => 'PWYW_PRICE',
    'VALUE' => $userPrice,
    'SORT'  => 100,
]);

$basket->save();

The CUSTOM_PRICE = 'Y' field is key. Without it, Bitrix will replace the entered price with the catalog price via CCatalogProductProvider when recalculating the cart.

Protection Against Recalculation

Even with CUSTOM_PRICE = 'Y', some handlers can reset the price. Subscribe to the OnSaleBasketItemRefreshData event and restore the price from the cart property:

AddEventHandler('sale', 'OnSaleBasketItemRefreshData', function(&$fields) {
    $basketItem = $fields['BASKET_ITEM'];
    $props = $basketItem->getPropertyCollection();
    $pwywProp = $props->getItemByCode('PWYW_PRICE');

    if ($pwywProp && $pwywProp->getValue() > 0) {
        $fields['PRICE']        = (float)$pwywProp->getValue();
        $fields['BASE_PRICE']   = (float)$pwywProp->getValue();
        $fields['CUSTOM_PRICE'] = 'Y';
    }
});

Minimum Price and UI Validation

The minimum threshold is checked twice: on the client (JavaScript) and server (PHP). Client check is for UX, server is mandatory.

On the product page, minimum price data is passed via data attributes or inline JS:

<div class="pwyw-widget"
     data-min-price="{{ $minPrice }}"
     data-suggested="{{ $suggestedPrice }}">
  <input type="number" name="pwyw_price"
         min="{{ $minPrice }}"
         value="{{ $suggestedPrice }}"
         step="1">
  <div class="pwyw-hint">Minimum amount: {{ $minPrice }} ₽</div>
</div>

Instead of Bitrix template engine — values are substituted in the component via $arResult or $arParams.

Display in Order and Personal Account

In the administrative order (sale.admin.order.edit) and in emails, show that the price was entered manually. Override the bitrix:sale.order.ajax component template — add output of the PWYW_PRICE property with a note "price specified by buyer".

In email templates like SALE_NEW_ORDER, add a block outputting cart properties via #BASKET_ITEMS# — the PWYW_PRICE property will already be included in standard substitutions.

Analytics and Minimum Amounts

To analyze real buyer behavior — what amounts they enter, how often below minimum — log all attempts in custom table b_pwyw_log:

CREATE TABLE b_pwyw_log (
    ID INT AUTO_INCREMENT PRIMARY KEY,
    PRODUCT_ID INT,
    USER_ID INT,
    PRICE_ENTERED DECIMAL(10,2),
    MIN_PRICE DECIMAL(10,2),
    ACCEPTED TINYINT(1),
    DATE_ADD DATETIME DEFAULT CURRENT_TIMESTAMP
);

Data from this table helps decide whether to adjust the minimum threshold.

Implementation Timeline

Option Description Timeline
Basic (single field, no limits) Infoblock properties + AJAX + cart handler 3–5 days
With Minimum and Logging + log table, server validation, UI hints 1 week
Full (HL block settings, analytics, SKU support) Admin interface + analytics report 1.5–2 weeks