Amirali YaghoutiSenior Software Engineer

webapp Case study

WooCommerce Customer Hub

The customer hub is the account area of our WooCommerce store rebuilt as a module of my a2-crm-plugin. A logged-in customer gets one screen for orders, addresses, loyalty points, wallet balance, tier status and recently viewed products.

The business problem

Stock WooCommerce gives My Account an order list, an address form and little else. Our store tracks loyalty points, wallet balances and customer tiers inside the CRM, and none of that data had a surface the customer could see, so the account area was the weakest page in an otherwise active store.

What I delivered

  • A customer-hub module inside a2-crm-plugin (includes/customer-hub/), rendered by a [customer_hub] shortcode with tabs for dashboard, orders, loyalty, wallet, recently viewed, profile and addresses.
  • A REST API under the customer-hub/v1 namespace: /me/summary, /me/orders, /me/loyalty, /me/wallet, /me/recently-viewed, plus read and write routes for profile and addresses.
  • A points engine where paid orders earn points per fixed amount unit, and tiers (bronze, silver, gold, VIP) resolve from lifetime points at 0, 500, 1500 and 5000.
  • Dedicated ledger tables (a2_ch_points_ledger, a2_ch_wallet_ledger) instead of stuffing balances into user meta.
  • Recently-viewed tracking capped at 20 products per customer with a 30-day expiry.

Technical approach

  • Points apply on woocommerce_order_status_changed when an order reaches a paid status, and reverse automatically on cancelled, refunded, failed or trash.
  • Every points write passes an idempotency check (a2_ch_points_entry_exists) so a replayed status change cannot double-credit a customer.
  • Product views are recorded on template_redirect for logged-in users only, then trimmed by a cleanup routine so the table cannot grow unbounded.
  • Tabs are configuration in the a2_ch_settings option; I removed tickets, downloads and wishlist from the available list because their REST routes did not exist yet, and a permanently blank tab is worse than a missing one.

Result and evidence

The hub is shipped and running in production as part of a2-crm-plugin, currently at version 3.2.17. I have not run a formal before-and-after measurement on it, and I will not dress that up; the evidence is that it has survived ongoing maintenance releases in daily use.

Commercial value

A customer who can check points, balance and tier in the account area has a reason to log in before buying, and the team does not have to relay that information by hand.

implementation-brief.readme

Readable implementation brief

implementation_brief {
  project: "WooCommerce Customer Hub"
  stack: "PHP (WordPress + WooCommerce), vanilla JS, MySQL"
  module: "a2-crm-plugin/includes/customer-hub: api, data, model, hooks, shortcodes, assets"
  api: "customer-hub/v1 -> /me/summary /me/orders /me/loyalty /me/wallet /me/recently-viewed /me/profile /me/addresses"
  tables: "a2_ch_points_ledger, a2_ch_wallet_ledger, a2_ch_recently_viewed"
  hooks: "woocommerce_order_status_changed -> points apply/reverse; template_redirect -> view tracking"
  loyalty: "tiers bronze/silver/gold/VIP at 0/500/1500/5000 lifetime points"
  status: "shipped in production; no formal before/after metrics recorded"
}

What this project shows

This module is a sample of how I extend WooCommerce without fighting it: custom tables where core has no model, core hooks where it does, and a REST layer that keeps the frontend honest.

It also shows restraint. Features without a working backend were cut from the tab list rather than shipped as empty screens, and every write that touches customer value was built to be reversible and traceable.