Skip to content

Wishlist

Flow ID: CF-17 | Module(s): eshop, Product domain | Complexity: Low

Business Overview

Logged-in customers save products for future purchase. Items added/removed via AJAX or REST, with automatic sync to Advisable AI bookmarks and Facebook Conversion API for retargeting.

What customers experience:

  • Click a heart icon on any product listing or detail page to save it
  • View saved products on /customer/wishlist (paginated, 36 per page)
  • Remove individual items or clear the entire wishlist
  • Toggle add/remove via AJAX with instant UI feedback (icon swap, toast notification)

Key business behaviors:

  • Requires login (redirects to homepage if not authenticated)
  • One entry per customer-product pair (duplicates silently ignored)
  • Syncs with AI bookmarks on add/remove (deferred task)
  • Facebook AddToWishlist event fired server-side on add via Meta Conversions API
  • Google GA4 add_to_wishlist event fired client-side via ecomnTag
  • Paginated display (36 per page) with product code parsing
  • Loyalty points calculated on wishlist page via calcLoyalty() hook

API Reference

REST Endpoints

MethodPathAuthDescription
GET/rest/product/wishlistCustomer JWTList wishlist items (filterable by id, customerId, productId)
GET/rest/product/wishlist/{id}Customer JWTGet single wishlist entry
GET/rest/product/wishlist/itemCustomer JWTGet entry by filter
POST/rest/product/wishlistCustomer JWTAdd product (customer ID from JWT)
POST/rest/product/wishlist/{id}Customer JWTUpdate entry
DELETE/rest/product/wishlist/{id}Customer JWTRemove (verifies ownership via resourceContext->getUserId())

Filters: id, customerId, productId Sorts: id, customerId, productId Relations: customer, product

Legacy AJAX

MethodPathDescription
POST (AJAX)/customer/wishlistAction/add/{productId}Add product — fires Facebook CAPI + AI bookmark
POST (AJAX)/customer/wishlistAction/remove/{productId}Remove product — removes AI bookmark
GET/POST/customer/wishlist_add/{productId}Add product (older endpoint)
GET/POST/customer/wishlist_remove/{productId}Remove product (older endpoint)
GET/POST/customer/wishlist_remove_allClear entire wishlist

Storefront Pages

URLDescription
/customer/wishlist/{offset}Paginated wishlist display (36/page)

Code Flow

Step 1: Add to Wishlist (AJAX via wishlistAction)

File: ecommercen/eshop/controllers/Adv_customer.php (line ~1131)

  1. Guard: Must be AJAX request with valid session (customer_id)
  2. Duplicate check: getCustomerProductIds($customerId) — skip if already in list
  3. Insert: wishlist_model->add_record({customer_id, product_id})
  4. Facebook CAPI: reportWishlistFacebookConversion($productId, 1) — deferred task
  5. AI bookmark: bookmarkToAdvisableAI($productId) — deferred task
  6. Response: JSON {status: 'success'}

Step 2: Facebook Conversion API Event

File: ecommercen/eshop/controllers/Adv_customer.php (line ~1163)

  1. Guard: Check FACEBOOK_CONVERSION.ENABLED registry setting
  2. Product data: Fetch product name and calculated final price from product_model
  3. Customer data: Fetch from customer_model by session ID
  4. Build payload: content_ids (with tracking prefix), content_name, content_type=product, currency, value
  5. Dispatch: Deferred task via FacebookConversionService->dispatchEvent(EventType::ADD_TO_WISHLIST, ...)

Step 3: Remove from Wishlist

File: ecommercen/eshop/controllers/Adv_customer.php (line ~1081)

  1. Delete: wishlist_model->remove($customerId, $productId)
  2. AI unbookmark: removeBookmarkFromAdvisableAI($productId) — deferred task
  3. Response: OK (text) or JSON depending on endpoint used

Step 4: Display Wishlist Page

File: ecommercen/eshop/controllers/Adv_customer.php (line ~955)

  1. Auth check: Redirect to homepage if no customer_id in session
  2. Fetch products: wishlist_model->get_products_with_paths($customerId, 36, $offset) — joins with product model for full product data
  3. Count: countProductsWithPaths({customer_id}) for pagination
  4. Hook: wishListExtra() — calls calcLoyalty() by default
  5. Render: Product grid with pagination, product code parsing

Step 5: Client-Side Behavior

File: assets/main/js/components/wishlist-actions.js

  1. Click handler: .wishlist_action elements with data-action, data-product_id, data-view_form
  2. AJAX POST: To /customer/wishlistAction/{action}/{productId} with optional AI recommendation ID
  3. GA4 event: On add, fires ecomnTag.add_to_wishlist_GA4() with product data from Vue state
  4. UI toggle: Swaps action data attribute, changes icon (heart/heart-broken), shows toast notification

Domain Layer

ComponentPath
REST Controllersrc/Rest/Product/Controllers/Wishlist.php
Servicesrc/Domains/Product/Wishlist/Service.php
WriteServicesrc/Domains/Product/Wishlist/WriteService.php
Validatorsrc/Domains/Product/Wishlist/Validator.php
WriteDatasrc/Domains/Product/Wishlist/WriteData.php
Entitysrc/Domains/Product/Wishlist/Repository/Entity.php
Repositorysrc/Domains/Product/Wishlist/Repository/Repository.php
WriteRepositorysrc/Domains/Product/Wishlist/Repository/WriteRepository.php
Legacy Modelecommercen/eshop/models/Adv_wishlist_model.php
JS Componentassets/main/js/components/wishlist-actions.js

Dual path: Legacy AJAX for storefront + REST for headless/admin.


Data Model

wishlist

ColumnTypeDescription
idint (PK, AI)Wishlist entry ID
customer_idint (FK)Customer who saved the product
product_idint (FK)Saved product reference

No timestamps on this table.


Client Extension Points

  • wishListExtra() hook: Override to add loyalty, upsell data (default calls calcLoyalty())
  • Facebook tracking: Override reportWishlistFacebookConversion() for custom event data
  • AI sync: Override bookmarkToAdvisableAI() / removeBookmarkFromAdvisableAI() methods
  • GA4 tracking: Client-side via ecomnTag.add_to_wishlist_GA4() in wishlist-actions.js
  • View: {client_views}/customer/wishlist/ — templates for wishlist page
  • REST ownership: destroy() in Wishlist controller verifies customer_id matches JWT user