Development of Wishlist Module for 1C-Bitrix
Standard Bitrix does not have a ready-made wishlist module for the catalog. There is the sale module with "delayed items" — they go into the cart with status Y in the DELAY field. This is not a wishlist: products are mixed with the cart logically and technically, there's no ability to create multiple lists, no support for guests with synchronization on login. Full-fledged wishlist is implemented as a separate module.
Data Storage
The module is located in local/modules/vendor.wishlist/. Two main tables:
Table b_wishlist — wishlist collections (a user can have multiple: "Want to buy", "Gifts", "Pending"):
| Field | Type | Purpose |
|---|---|---|
| ID | int auto_increment | Primary key |
| USER_ID | int | User ID (NULL for guests) |
| SESSION_ID | varchar(64) | Guest session hash |
| TITLE | varchar(255) | List title |
| IS_PUBLIC | tinyint(1) | Can be shared by link |
| PUBLIC_HASH | varchar(32) | Unique hash for public URL |
| CREATED_AT | datetime | — |
Table b_wishlist_item:
| Field | Type | Purpose |
|---|---|---|
| ID | int auto_increment | — |
| LIST_ID | int | FK to b_wishlist |
| PRODUCT_ID | int | Product offer ID |
| ELEMENT_ID | int | Iblock element ID (parent product) |
| ADDED_AT | datetime | — |
| NOTE | text | User's personal note about the product |
Guest to Authenticated User Synchronization
When a user logs in, the OnAfterUserLogin event handler runs:
\Bitrix\Main\EventManager::getInstance()->addEventHandler(
'main',
'OnAfterUserLogin',
[WishlistMerger::class, 'merge']
);
The merge method finds the anonymous list by SESSION_ID, transfers products from it to the user's main list (with duplicate check via SELECT before INSERT), then deletes the anonymous list. If the user doesn't have any list yet, the anonymous list is simply reassigned via UPDATE b_wishlist SET USER_ID = ?, SESSION_ID = NULL WHERE SESSION_ID = ?.
"Add to Wishlist" Button on Product Card
The button sends AJAX request to the vendor:wishlist.button component. The component accepts PRODUCT_ID and ACTION (add/remove/toggle), performs the operation and returns JSON with new state.
On catalog page, button states are initialized once: on page load, a single request returns array of PRODUCT_ID that current user already has in wishlist. JavaScript marks corresponding buttons without repeated server requests.
// Getting all product IDs in wishlist for current user
$items = WishlistItemTable::getList([
'filter' => ['=LIST_ID' => $listId],
'select' => ['PRODUCT_ID'],
])->fetchAll();
$productIds = array_column($items, 'PRODUCT_ID');
Public Lists and Sharing
Each list can be made public. In this case, PUBLIC_HASH is generated via \Bitrix\Main\Security\Random::getString(32). URL like /wishlist/share/abc123/ opens the list for any visitor in view mode. The viewer can add individual items to their cart, but cannot edit someone else's list.
The feature is useful for gift lists: a user compiles a desired gifts list and sends the link to relatives.
Price Drop Notifications
An optional but popular feature: if a product in wishlist gets cheaper, the user receives an email notification. Implemented via agent (\Bitrix\Main\Agent) or cron task:
- Agent runs daily, iterates unique
PRODUCT_IDfromb_wishlist_item. - For each, gets current price via
\CCatalogProduct::GetByID()orPrice::getList(). - Compares with price saved in
LAST_PRICEfield (added tob_wishlist_itemtable). - On price drop, sends email event
WISHLIST_PRICE_DROP.
Counter in Header
Product count in wishlist is displayed in header. To avoid heavy query on every page load, counter is cached in $_SESSION['WISHLIST_COUNT'] and invalidated on each list change. Header component reads value from session — single PHP call without DB access.
Development Timeline
| Scale | Content | Duration |
|---|---|---|
| Basic | One list, DB storage, AJAX button, header counter | 4–5 days |
| Standard | + Guest/user merge, wishlist page in cabinet, multiple lists | 7–10 days |
| Extended | + Public lists, price drop notifications, list export | 12–15 days |







