Skip to main content

Product Waitlist

Overview​

The Waitlist module lets a shopper register interest in an out-of-stock product and be emailed when it returns. A join form is drawn on the product page, entries are held per product or variation, and the emails go out either automatically when stock returns or on demand from the admin screen.

It is for stores that want a queue on their out-of-stock lines and want to control when the "it's back" email is sent — the delay setting exists so a restock can be checked before hundreds of customers are told.

It overlaps with Back-in-Stock Notifications, which does the same job with double opt-in, demand analytics and a notification log. This module is the simpler of the two: consent is a single required checkbox, and there is no opt-in confirmation step.

Availability​

ItemValue
Module keywaitlist
TierPremium
Entitlement keywaitlist
Admin tabwaitlist, under Product Experience
Enabled optionaiowc_module_enabled_waitlist (off until turned on)
REST namespaceaiowc/v1

Enabling the module creates the two tables below, seeds the defaults and schedules both jobs. Disabling it unschedules them.

Settings​

Stored in the option row aiowc_wl_settings, written with autoload off. They are seeded only when that row is empty.

Stored keyDefaultMeaning
enable_waitlisttrueAccept new entries. Off makes every join attempt fail with waitlist_disabled.
require_loginfalseRefuse a guest join with login_required.
auto_notifytrueSend automatically when stock returns. Off means only the admin control sends.
notification_delay0Minutes to wait after a restock before sending. Above zero, a single event is scheduled instead of sending inline.
max_waitlist_size0Cap per product; 0 means no cap. A full list refuses with waitlist_full.
priority_window_hours24Seeded but read nowhere — see Known gaps.

The settings prefix aiowc_wl_ is shared with the Wishlist module, so both write to the same aiowc_wl_settings row. See Known gaps.

Joining​

WaitlistService::joinWaitlist() refuses in this order, each with its own error code: an invalid email address, missing consent, the module being disabled, a guest when require_login is on, an unknown product, a product that is already in stock, an address already on that product's list, and a list that has reached max_waitlist_size. Only then is the entry written, with status active and consent recorded.

Admin screen​

The Product Waitlist tab sends the back-in-stock emails. You enter a product id and an optional variation id, then either Show who is waiting — which reads GET /waitlist/entries for that product — or Notify everyone waiting, which goes out after a confirmation. The screen states plainly that real email reaches real customers with no undo, and reports how many were sent and how many failed.

REST API endpoints​

All routes are on aiowc/v1 and answer with the { success, data, message } envelope.

MethodPathPurposePermissionRequired args
POST/waitlist/joinJoin the waitlist for a product or variation.Open to guests, REST nonce, 30 requests a minuteproduct_id, email, consent
DELETE/waitlist/{id}/leaveLeave an entry. Ownership is checked against the signed-in user.Signed-in userid
GET/waitlist/my-itemsThe signed-in user's own entries.Signed-in user–
GET/waitlist/entriesA page of entries, optionally narrowed by product_id. per_page is capped at 50, default 20.manage_woocommerce–
POST/waitlist/notify-allEmail everyone waiting for a product. Sends immediately; returns sent and failed.manage_woocommerceproduct_id

notify-all does nothing and reports zero when the product is not in stock at the time it runs.

WooCommerce integration​

HookPriorityWhat the module does
woocommerce_single_product_summary32Draws the join form.
woocommerce_product_set_stock_status10On instock, triggers notifications for that product.
woocommerce_variation_set_stock_status10On instock, triggers notifications for that variation's parent and variation.

Both stock hooks respect auto_notify. When notification_delay is above zero they schedule a single aiowc_waitlist_check_stock event instead of sending inline.

Shortcode [aiowc_waitlist_form] renders the join form outside the product page.

Email is sent with wp_mail().

Database schema​

TableHolds
{prefix}aiowc_waitlistsOne row per waiting shopper: product, variation, user id, email, status, consent, notified date.
{prefix}aiowc_waitlist_notificationsOne row per notification sent, with an opened_at column.

Background jobs​

HookIntervalWork
aiowc_waitlist_check_stockhourlyWalks the products with active entries and notifies the ones back in stock. Returns immediately when auto_notify is off.
aiowc_waitlist_cleanupdailyRemoves stale entries.

Entitlement limits​

waitlist is an on/off grant with no numeric cap. The one numeric limit is max_waitlist_size, a store setting, and the 50-row page cap on the entries route.

Health check​

The module reports a warning when its tables are missing or WooCommerce is inactive. Otherwise it reports that it is functioning normally.

Known gaps​

  • The settings prefix collides with Wishlist. Both modules declare SETTINGS_PREFIX = 'aiowc_wl_' and both persist to aiowc_wl_settings. Waitlist only seeds its defaults when that row is empty, so if Wishlist is enabled first the row already exists and Waitlist's keys are never written — its service then falls back to its own hardcoded defaults and the admin cannot change them.
  • No settings route and no settings screen. Fixed 2026-09-14: the settings are editable from the Settings tab over GET/PATCH /waitlist/settings. 🔴 The prefix collision above still applies — a form cannot help if Wishlist owns the row the values are written to.
  • priority_window_hours is seeded and never read.
  • The notifications table has an opened_at column, but nothing writes it — there is no open tracking.
  • The delayed path schedules the hourly job's hook as a one-off, so it notifies every product that is back in stock, not only the one that triggered it.