Skip to main content

Auctions

Overview​

Auctions adds an auction product type with three bidding models. A standard auction takes the highest bid. A proxy auction takes a customer's maximum and bids on their behalf up to it, so they win at the smallest increment over the next bidder rather than at their ceiling. A sealed auction hides every bid until the auction closes.

Around that sit the mechanics a real auction needs: a reserve price that must be met, an optional buy-now price, bid increments that can be fixed or tiered by value, and anti-sniping — a bid placed in the final minutes extends the auction, up to a cap, so an auction cannot be won by being last rather than highest.

When an auction ends, a winner is resolved, given a payment window and reminded; if they do not pay, the runner-up can be offered a second chance and the auction can be relisted.

It is for stores selling by competitive bidding.

Availability​

ItemValue
Module keyauctions
TierPremium
Entitlement keyauctions
Admin tabauctions
Enabled optionaiowc_module_enabled_auctions (off until turned on)
REST namespaceaiowc/v1
Product typeAuction

Enabling the module creates the four tables below and schedules five jobs.

registerHooks() performs no licence check of its own; the module registry applies the entitlement gate centrally. It registers the product type, the frontend, the jobs and the WooCommerce email classes.

Settings​

This module declares no DEFAULTS constant. Settings are read and written through GET/PUT /auctions/settings, and most of what governs an auction lives on the auction row itself.

The auction​

FieldMeaning
auction_typestandard, proxy or sealed.
statusdraft, scheduled, active, ended, closed or cancelled.
start_datetime, end_datetime, original_end_datetimeWhen it runs, and when it was originally due to end before extensions.
timezoneStored per auction rather than assumed.
starting_priceWhere bidding opens.
reserve_price, reserve_metA floor below which the item is not sold, and whether it has been reached.
buy_now_price, buy_now_enabledAn immediate purchase price.
current_bid, bid_countThe running state.
increment_type, increment_value, increment_tiersfixed or tiered; tiers let the step grow with the price.
anti_sniping_enabled, _minutes, _extension, extension_count, max_extensionsThe sniping guard and how often it has fired.
winner_user_id, winner_bid_id, winning_priceThe outcome.
payment_due_hoursHow long the winner has to pay. Defaults to 48.
pay_now_token, pay_now_expiresA one-off link letting the winner pay, with its own expiry.
allow_auto_relistWhether an unsold auction relists itself.
featuredWhether it is promoted in listings.

Keeping original_end_datetime alongside end_datetime is what makes an extended auction auditable — you can see it was extended, and by how much.

Bids​

FieldMeaning
bid_amount, max_bidThe bid placed, and the ceiling for a proxy bid.
is_proxy, is_sealed, is_winningWhat kind of bid it is and whether it currently leads.
user_id, user_email, user_nameWho placed it.
ip_address, user_agentRecorded for every bid. See the limits below.
triggered_extensionWhether this bid caused an anti-sniping extension.

Bidding is rate-limited, through the aiowc_auction_max_bids_per_minute filter.

Ending an auction​

A closing job runs every minute, which is what makes an auction end at its stated time rather than at the next hourly tick. It resolves the winner, sets the winning price, and issues the pay-now token.

Where no bid met the reserve, the auction ends with no winner and — if allow_auto_relist is set — relists itself. Where the winner does not pay within payment_due_hours, reminders go out on configurable thresholds and the store can offer the item to the next bidder.

Admin screen​

The Auctions tab lists and manages auctions — start, end, cancel, relist, in bulk or one at a time — shows statistics and a winners list, offers a second chance or sends a payment reminder, browses bids by auction or by user, exports auctions, and reads an auction's log.

It also carries diagnostics with a repair action: GET /auctions/diagnostics reports inconsistencies and POST /auctions/diagnostics/repair fixes named ones. That is unusual in this plugin and useful for a module whose state is driven by timed jobs.

REST API endpoints​

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

MethodPathPurposeRequired args
GET / POST/auctionsList and create auctions.product_id, end_datetime, starting_price on create
GET / PATCH / PUT / POST / DELETE/auctions/{id}Manage one auction.id
POST/auctions/{id}/start / /endStart or end it now.id
POST/auctions/{id}/cancelCancel it, with a reason.id, reason
POST/auctions/{id}/relistRelist it with a new end time.id, end_datetime
GET/auctions/{id}/logsIts history.id
POST/auctions/bulk/end / /bulk/cancelAct on several at once.ids
GET/auctions/{auction_id}/bidsBids on one auction.auction_id
DELETE/auctions/{auction_id}/bids/{bid_id}Retract a bid — a reason is required.auction_id, bid_id, reason
GET/auctions/winnersAuctions with a winner.–
POST/auctions/winners/{id}/remindRemind a winner to pay.id
POST/auctions/winners/{id}/offer-secondOffer the item to the next bidder.id
GET/auctions/statistics / /exportReporting and export.–
GET/auctions/diagnosticsDetected inconsistencies.–
POST/auctions/diagnostics/repairRepair named inconsistencies.repairs
GET / PATCH / PUT / POST/auctions/settingsRead and write the settings.–
GET/bids, /bids/{id}, /bids/recent, /bids/statistics, /bids/user/{user_id}Browse bids across auctions.–
GET/public/auctionsThe public auction listing.Public, rate-limited

Requiring a reason to retract a bid or cancel an auction is a deliberate choice: both are interventions in a competitive process, and the reason is recorded.

WooCommerce integration​

AreaHooks
Product typeproduct_type_selector, woocommerce_product_class, woocommerce_product_data_tabs / _panels, woocommerce_process_product_meta_auction
Product pagewoocommerce_single_product_summary, woocommerce_product_tabs, woocommerce_get_price_html
Cartwoocommerce_add_to_cart_validation, woocommerce_cart_item_class, _cart_item_name, _cart_item_quantity, woocommerce_before_calculate_totals
Checkoutwoocommerce_checkout_process, _checkout_create_order_line_item, _checkout_order_processed
Order statuswoocommerce_order_status_processing, _completed, _cancelled, _refunded
Order displaywoocommerce_order_item_meta_start, woocommerce_admin_order_item_headers / _values
Accountwoocommerce_account_menu_items
Emailswoocommerce_email_classes — seven auction emails ship as real WooCommerce email classes
Admin listmanage_product_posts_custom_column
Otherquery_vars, template_redirect, body_class

Shortcodes [aiowc_active_auctions], [aiowc_auction_search], [aiowc_my_auction_bids] and [aiowc_my_watchlist].

The cart hooks matter because an auction win is not an ordinary add-to-cart: the quantity is fixed at one and the price is the winning price, so the customer cannot change either.

Database schema​

TableHolds
{prefix}aiowc_auctionsThe auction, as described above.
{prefix}aiowc_auction_bidsEvery bid: amount, proxy ceiling, flags, bidder identity, IP address and user agent, whether it triggered an extension.
{prefix}aiowc_auction_watchlistWhich customers are watching which auctions.
{prefix}aiowc_auction_logsThe auction's history, pruned on a retention filter.

Background jobs​

HookIntervalWork
aiowc_auction_closingevery minuteEnds auctions at their stated time and resolves the winner.
aiowc_auction_startevery 15 minutesStarts scheduled auctions.
aiowc_auction_ending_soonevery 15 minutesNotifies watchers and bidders that an auction is closing.
aiowc_auction_payment_reminderhourlyChases winners who have not paid.
aiowc_auction_cleanupdailyPrunes logs past the retention window.

The every-minute closing job is the one to check first when auctions do not end on time: it depends on WP-Cron actually firing, which on a low-traffic site means a real system cron rather than page-visit-triggered cron.

Action hooks for integrators​

Lifecycle: aiowc_auction_created, _updated, _deleted, _status_changed, _extended, _bid_placed, _user_outbid, _buy_now, _auto_relist, aiowc_sealed_bids_revealed.

Notifications: aiowc_auction_started_notification, _ended_notification, _ended_seller_notification, _no_winner_notification, _winner_notification, _second_chance_notification, _cancelled_notify, _payment_reminder, _payment_overdue, _payment_confirmation, and the two sealed-auction notifications.

Filters: aiowc_auction_max_bids_per_minute, aiowc_auction_log_retention_days, aiowc_ending_soon_notification_windows, aiowc_payment_reminder_thresholds.

Entitlement limits​

auctions is an on/off grant with no cap on auctions, bids or watchlist entries. The bid rate limit is a filter.

Health check​

The module reports a warning when its tables are missing or WooCommerce is inactive, and otherwise reports that it is functioning normally. The diagnostics route gives considerably more detail, including inconsistencies it can repair.

Known gaps​

  • Every bid stores the bidder's IP address and user agent. That is defensible for an auction — it is the record that makes shill bidding and disputes investigable — and it must appear in the store's privacy notice. Since 2026-09-13 it is bounded: the cleanup job nulls ip_address and user_agent on bids older than aiowc_auction_bid_retention_days, which defaults to whatever aiowc_auction_log_retention_days resolves to, so a store has one retention knob unless it deliberately wants two.
  • 🔴 The bid row itself is kept, and only the two identifying columns are cleared. The row is the auction's record of a completed sale; deleting it would rewrite a settled result.
  • 🔴 The closing job runs every minute, and WP-Cron only fires on a page request. On a quiet store the sweep runs when the next visitor arrives, so an auction can accept bids past its end time. A store selling by auction needs a real system cron plus DISABLE_WP_CRON; this is a deployment requirement, not a setting.
  • The closing job runs every minute and the module's correctness depends on it. On a site where WP-Cron only fires on page visits, a quiet period means auctions close late. A real system cron is effectively required.
  • The module has no settings constant, so the defaults for a new auction are not stated in one place in the code.
  • A sealed auction's bids are hidden from customers, but they are readable by any administrator through the bids routes while the auction is still running.
  • Second-chance offers and relisting are manual actions, except where allow_auto_relist is set on the auction.