Skip to main content

Directory Theme class reference

20 min read

Auction Theme — Class reference

The 30 classes that make _at behave differently from the shared Directory core. Generated from the theme source.

← Back to Auction Theme features

AuctionClose AuctionClose.php​

Per-lot auction close-out — scheduled with wp_schedule_single_event() at the lot's exact end time (set by ListingEditor::saveAuctionLot()), rather than _sp\Expiry's coarse daily cron: an auction end time needs minute precision, not "sometime today". On close: no bids (or reserve not cleared) closes the lot with no sale; a winning bid creates a payment order via Checkout::createLotOrder() and emails the winner. Buy-it-now lots are closed immediately by Bidding::place() instead (see scheduleFor()/unschedule() below), which is why this class only handles the "ran out the clock" path.

API
register()scheduleFor()unschedule()close()notifyWinner()
inc/_at/AuctionClose.php

AuctionLot AuctionLot.php​

Auction lot data for a listing — bidding type, starting/current bid, reserve, buy-it-now, bid increment, end time and status. Mirrors Ppt\_sp\Product's shape (static accessors over plain post meta on the same listing_type CPT, no new CPT) but for a bid-driven price instead of a fixed one. Bidding types (chosen per lot, in the submission/edit form): - timed : standard ascending-bid auction with an end time, optional reserve and optional buy-it-now (see Bidding::place()). - live : same mechanics as timed, just a shorter default duration and a faster front-end poll interval — no separate data or code path. - penny : each bid consumes one prepaid bid credit (BidCredits) instead of a chosen amount, bumps current_bid by exactly bid_increment, and extends end_time by a few seconds (the anti-snipe "time added" mechanic bidding-fee auctions rely on). On save, the current bid (or starting bid, pre-first-bid) mirrors into the same searchable price meta (SearchPage::PRICE_META) that Product mirrors into, so price sort/filter/range keep working for lots exactly as for products — see ListingEditor::saveAuctionLot().

API
has()biddingType()startingBid()currentBid()reservePrice()reserveMet()buyNowPrice()weight()buyNowAllowed()bidIncrement()defaultIncrement()antiSnipeWindow()maxBidCeiling()maxBidMultiple()maxNextBid()minNextBid()endTimestamp()activeType()lengthPresets()lengthPresetSeconds()defaultLengthPreset()bidCount()status()winnerId()
inc/_at/AuctionLot.php

BidCredits BidCredits.php​

Prepaid bid-credit balance for penny/bidding-fee auctions. A buyer purchases a pack of N credits once through the normal Payments\CheckoutFlow checkout (see Bidding::creditPackPlan()); each bid on a penny-type lot then just decrements this balance server-side — no live gateway call per bid. Stored as plain user meta (a simple integer counter). grant() is idempotent per order reference so a re-run/duplicate callback never double-credits — the same dedupe spirit as _sp\Expiry's reminder-window flags.

API
balance()grant()consume()
inc/_at/BidCredits.php

Bidding Bidding.php​

Bid placement — the one write path shared by all three bidding types (timed, live, penny; see AuctionLot's class docblock). Registers a logged-in-only AJAX endpoint to place a bid, and a public read-only AJAX endpoint the front-end polls for the current price/time-remaining (the "AJAX polling, no WebSocket" realtime approach decided for this build). Every amount is re-validated server-side here — the client never gets to set the price it pays, same discipline as _sp\Cart::add(). PROXY BIDDING (timed + live lots). The amount a bidder submits is their private MAXIMUM, not the price they pay: placeProxyBid() seats them at the lowest amount that takes the lead (the standing maximum plus one increment, capped at their own) and holds the rest back. When a rival bid arrives the standing proxy auto-responds — a real bid row flagged is_auto — so Bids::highest() always names the true leader at the true price and AuctionClose needs no proxy awareness at all. A maximum is never rendered, polled or emailed: only the bidder who set it, and the resolved visible price, ever leave this class. Penny lots keep the credit-driven fixed-increment path (no maximum, no proxy), and Buy-it-now still ends the lot instantly, ahead of any proxy resolution.

API
register()enqueueAssets()ajaxPlace()ajaxStatus()place()ownMaxLabel()
inc/_at/Bidding.php

BidPass BidPass.php​

One-time "bidding pass" — an optional, site-wide gate the admin can switch on (Settings ▸ Lots ▸ Auction Bidding). When enabled with a price set, every member must make a single purchase before they may place ANY bid; the purchase is a normal order in the billing system (Ppt\_at\Checkout, kind 'bidpass') and, once paid, a flag on the member's account unlocks bidding for good. The paid flag is plain user meta with an idempotent per-order-ref guard, mirroring BidCredits. The lock itself is enforced server-side in Bidding::place() (the authoritative check) and reflected in the bid box + member area so a locked user is shown how to buy the pass rather than a dead bid form.

API
enabled()price()required()hasPaid()mustPurchase()purchaseUrl()grant()
inc/_at/BidPass.php

Bids Bids.php​

Bid storage for auction lots — a dedicated DB table (not post meta) so the full bid history per lot is queryable and append-only, while AuctionLot's post meta (current_bid, bid_count) stays the fast-read summary the front-end polls. Table/versioning pattern copied from Ppt\_sp\Cart::install().

API
register()table()install()record()maxOf()highest()proxyLeader()userMaxOnLot()history()count()clearLot()byUser()lotsBidByUser()userHighestOnLot()
inc/_at/Bids.php

Cart Cart.php​

Auction cart — lets a winner batch up several won-but-unpaid lots and pay for them in one checkout, the shop-cart way (Ppt\_sp\Cart) but far simpler: a lot is a single fixed-price line (no variants, no quantity, no coupons) and only a signed-in winner can ever hold one, so the cart is just a list of lot ids in user meta — no cart table, guest cookie or login-merge needed. A lot is cart-eligible only while the current user is its winner AND its payment is still outstanding (Checkout::orderForLot() not complete); items() re-checks that on every read and silently drops anything that no longer qualifies (paid elsewhere, re-listed, etc.), so the stored list is self-healing. Pricing reuses the same shared machinery as the single-lot checkout — Ppt\Checkout\Shipping (combined weight), CheckoutFlow::totals() (tax) and _at\Commission (summed per lot) — see totals().

API
register()eligible()add()remove()clear()has()items()count()isEmpty()lotIds()subtotal()weight()totals()url()headerIcon()addUrl()removeUrl()renderPage()handlePost()handleAjax()
inc/_at/Cart.php

Checkout Checkout.php​

Auction checkout — a sibling to Ppt\Payments\CheckoutFlow and Ppt\_sp\Checkout (not a modification of either), handling the two payment kinds an auction lot needs that neither of those covers: - 'lot' : the winning bidder paying for a lot they won (by close-out or buy-it-now). The order is created up front by AuctionClose::close() or Bidding's buy-it-now path — NOT here at pay time, since the amount is fixed the moment the lot is won — and this class just re-validates ownership/status and hands off to the gateway. - 'credits' : a prepaid bid-credit pack for penny/bidding-fee auctions, created at pay time like a normal one-off purchase. Reuses the same shared machinery CheckoutFlow does: the ppt_payment_gateways registry (Ppt\Admin\Payments), the exact ppt_gateway_start/ppt_gateway_verify filter contracts, the same ppt_orders CPT (Ppt\Admin\Orders), the same /checkout/ + /callback/ virtual pages (Ppt\Frontend\Pages), and the same receipt email templates. Order refs are prefixed AUCT- (vs CheckoutFlow's PP- and _sp\Checkout's SHOP-) so Pages::content() can route /callback/ to whichever class owns that order. Shipping + tax apply to a 'lot' order (a won physical item): the delivery address is collected on this checkout, then shipping and tax are priced with the SAME shared machinery the Shop uses — Ppt\Checkout\Shipping (weight bands / carrier plugins, off the lot's AuctionLot::weight()), Ppt\Checkout\Address (the address card + validation), and CheckoutFlow::totals() (tax) — all driven by the one shared admin config in Ppt\Admin\Checkout (Design ▸ Checkout). Since the winner's address isn't known until they reach this page, the lot order is created at close-out with just the item price (the winning bid), and shipping/tax are finalised here at pay time. Credit packs and bidding passes are digital, so they're charged as-is with no address/shipping.

API
register()lotCheckoutUrl()creditsCheckoutUrl()bidPassCheckoutUrl()commissionCheckoutUrl()cartCheckoutUrl()callbackUrl()isAuctionRef()creditPacks()creditPack()handlePay()createLotOrder()lotOrderView()orderForLot()commissionOrderForLot()createCommissionOrder()raiseSaleCommissions()needsShipping()isPaid()lotItemPrice()lotTotals()ajaxShippingQuote()markPaid()renderCheckout()
inc/_at/Checkout.php

Comments Comments.php​

Listing comments (member Q&A) — the Auction fork's replacement for star reviews. Built on native WordPress comments so they moderate and store like any comment, but stamped with the comment type "ppt_qa" (the identifier that distinguishes them from ordinary blog comments, listing reviews and reports in the admin). There is no rating — this is a plain "ask a question / leave a comment" thread. Rendered in the single-listing "Comments" section (list + add-comment form). Managed in PPT ▸ Comments (Ppt\Admin\Comments): they list under "All", and the toolbar's "Q&A" type filter narrows to just these.

API
register()open()stampType()count()all()renderList()renderForm()
inc/_at/Comments.php

Commission Commission.php​

House commission on auction sales — an optional cut the site takes on every lot that sells. The admin turns it on and sets either a percentage or a fixed amount (Checkout ▸ Commission); it's then added on top of the winning bid at checkout, shown on the lot's buy box, and itemised on the order + invoice. Settings live in the shared ppt_checkout option under the commission section (read via Ppt\Admin\Checkout::get()), alongside tax/shipping/coupons — this is a checkout charge, not a per-lot field, so it belongs with the other cart rules.

API
enabled()type()amount()applies()on()label()sellerEnabled()sellerType()sellerAmount()sellerApplies()sellerOn()sellerLabel()
inc/_at/Commission.php

DemoAccounts DemoAccounts.php​

Auction — what the typed DEMO members walk into on top of the shared furnishing (Account\DemoFurnish: favourites, follow, inbox thread, review). the SELLER (AccountType::SOLO) three seeded lots (DemoLogin lends them — the count is raised here from one); the BIDDER (AccountType::CLIENT) a bid on each open lot, placed through the fork's own Bidding::place() so the lot page, the seller's hub and the bidder's hub all agree. Bids are best-effort: a lot that has ended, a bid pass the site insists on, or an auction with no reserve information simply gets no bid. Gated to the auction profile by Theme::boot()'s fork-gating (this is Ppt_at*).

API
register()lendCount()pair()unpair()
inc/_at/DemoAccounts.php

DemoRefresh DemoRefresh.php​

Keeps a demo/showroom auction alive: a SEEDED SAMPLE lot never really ends — when its clock runs out the lot is rolled forward onto a fresh countdown inside a 30-day window and reset to a never-bid state, so an Auction Theme demo left running for months still reads as a live marketplace instead of a wall of "Ended" cards. Scope — this is deliberately narrow, on the same principle as Admin\Migrations' backfills: it acts ONLY on listings carrying the sample-data flags (SampleData::DEMO_META / BULK_META), so a lot a real member created is never touched, whatever state the site is in. It is not gated on preview/demo mode, because a showroom install has designs activated (which turns preview off) yet is exactly the site that needs this. A client who wants it off can return false from the ppt_at_demo_refresh_enabled filter — or, more usually, just delete the demo listings. Two triggers, for precision and for catch-up: 1. AuctionClose::close() — the per-lot event already scheduled at the exact end time hands a demo lot here instead of closing it, so the rollover happens to the minute. 2. The hourly sweep below — picks up lots whose scheduled event was missed (WP cron only fires on traffic), lots that ended before the theme gained this feature, and buy-it-now lots, which unschedule their close event entirely.

API
register()schedule()unschedule()enabled()isSeeded()rollIfDemo()roll()sweep()
inc/_at/DemoRefresh.php

Single-listing gallery styles. The admin picks one of four layouts on the Design ▸ Listings tab (stored in the ppt_design option via Branding), and the single-listing template renders the chosen layout for the listing's images. standard — large hero photo + thumbnail strip (click to swap) [default] grid — all photos in a tiled grid (first one featured) carousel — a swipeable/scroll-snap slider with prev/next tall — full-width photos stacked vertically (good for portraits)

API
styles()locked()current()isFullSpan()render()css()
inc/_at/Gallery.php

Geocoder Geocoder.php​

Bulk geocoder — fills in lat/lng for existing listings that have an address but no coordinates (e.g. listings created before the editor's map picker existed), so they get a precise map marker and the "Distance from me" feature. Uses the site's Maps provider (Settings ▸ API keys): Google / Mapbox geocoding APIs (their key), or OpenStreetMap Nominatim (keyless, rate-limited to ~1 req/sec with an identifying UA). A small box on the PPT Listings screen runs it in batches over AJAX. Listings that can't be geocoded are flagged (_ppt_geo_failed) so they aren't retried forever.

API
register()geocode()pendingCount()ajaxBatch()assets()box()
inc/_at/Geocoder.php

ListingActions ListingActions.php​

Per-listing visitor actions shown on the single-listing section nav: - Add to favorites — toggles the listing in the member's saved list (user meta ppt_favorites); the account page shows them. Logged-in only; guests are routed to sign-in. - Report — flags the listing to the site admin. The reason is stored as a comment on the listing (type ppt_report, a custom approval status so it stays hidden from the front-end and the normal comment-moderation tabs) and also emailed to the admin. Reports are reviewed in the admin Comments screen's dedicated "Reports" tab. Open to guests and members.

API
register()favIds()favHas()favToggle()favListingIds()ajaxFav()ajaxReport()assets()favButton()reportButton()
inc/_at/ListingActions.php

ListingCard ListingCard.php​

The canonical listing card — the single, theme-wide way a lot is shown as a card. Every auction surface (search results, single-page "related", and any live lot-grid blocks) renders through here, so a lot looks the same everywhere. Mirrors Ppt\_sp\ListingCard's shape and markup exactly (same .ppt-lc-* classes/CSS) — only the data behind price and sold_out differs: a bid box has no "Add to cart" concept, so buyable is always false here and price shows the current bid (mirrored into the same searchable price meta _sp\Product also mirrors into), not a fixed price. Data-source agnostic: fromPost() maps a real listing_type record and fromSample() maps a curated demo row into the same normalized shape, which render() draws. Normalized shape: name, link, img, cat, rating, desc, desc_long, price, end_ts (int), time_label (string), city, dist, featured (bool), highlighted (bool), badge (string), id, buyable (bool), sold_out (bool) The card foot shows the auction countdown (end_ts / time_label), not the price or a star rating: a lot's live "time remaining" is the thing a buyer scans a results grid for. price (current bid, mirrored into the searchable price meta) stays in the shape so sort/filter keep working — it's just not drawn on the card.

API
fromPost()fromSample()render()
inc/_at/ListingCard.php

ListingEditor ListingEditor.php​

Listing editor — the shared brain behind the two listing-edit screens: - Admin : PPT-styled screen at ?page=ppt_listings&edit=<id> (Chrome shell), rendered by Admin\Listings when the edit param is present. - Member : front-end screen at /account/listing/<id>/ inside the Member Hub, rendered by Account\MembersPage for a listing the member owns. Both POST to admin-post.php (action ppt_listing_save) and run through the one save() below, so the field set, sanitising and persistence live in a single place. The mode (admin|member) decides which extras are honoured: admins get status, author, slug, featured/verified and the "edit only" custom fields; members get a friendly subset scoped to their own listing. Fields = core (title, description, category, tags, featured image, gallery, FAQ) + every field defined in the Custom Fields admin (Admin\Fields / option ppt_fields), stored as post meta keyed by the field key — which is what the single-listing template already reads.

API
register()newUrl()handleNew()submissionsOpen()memberCanAdd()canEdit()adminEditUrl()memberEditUrl()applicableFields()locationKeys()coordKeys()mapPickerReady()mapConfig()locationFields()socialNetworks()socialValue()socialIcon()hoursDays()hoursValue()normTime()bookingValue()bookingsEnabled()bookingProviderAllowed()currentCategoryId()
inc/_at/ListingEditor.php

ListingFaq ListingFaq.php​

Single-listing FAQ. Reads per-listing FAQ items from the faq post meta (an array of ['q' => …, 'a' => …]). A live listing shows only its own saved FAQ — when it has none the section is omitted rather than filled with fabricated entries. Demo/preview mode supplies sample FAQ via DemoContent so a fresh design isn't empty. Populate a listing's own FAQ by saving faq meta, inject a site-wide default set via the ppt_listing_faq_default filter, or adjust the final list with the ppt_listing_faq filter.

API
items()
inc/_at/ListingFaq.php

ListingLocation ListingLocation.php​

Single-listing "Location" section — the richer location block: the full formatted address, an interactive map (ListingMap, precise when the listing has coordinates), a "Get directions" button, and a "Distance from you" control (browser geolocation → straight-line distance to the listing). Self-contained: it prints its own scoped CSS + JS once, so single.php just calls render().

API
address()coords()has()render()
inc/_at/ListingLocation.php

ListingMap ListingMap.php​

The single-listing "Location" map. Uses the site's Maps provider setting (Settings ▸ API keys — the same ppt_maps_provider filter the search map reads). When the listing has stored coordinates (lat/lng, set by the editor's map picker) the map centres on them precisely and drops a named marker; otherwise it falls back to geocoding the address string: google / mapbox(fallback) → a keyless Google Maps embed osm → a Leaflet map (marker from coords, else Nominatim) Map libraries load from their CDNs — the owner-approved front-end map exception.

API
render()
inc/_at/ListingMap.php

ListingSections ListingSections.php​

PPT — configurable single-listing sections. The admin (Design ▸ Listings ▸ "Listing page sections") gets a sortable list of on/off toggles for the optional feature blocks a listing page can carry — Booking, Business hours, Maps & Location, FAQ, Comments. Turning one OFF removes it from BOTH the single listing page and the listing submission/edit form; the order of the list controls the order the (main-column) sections appear in. Config lives in the shared design option (Branding::OPTION = ppt_design) under the listing_sections key: { order:[keys…], enabled:{key:0|1} }. Anything not saved yet defaults to ON, in the catalog order — so existing sites are unchanged until the admin edits the list.

API
supported()catalog()config()order()enabled()orderedAmong()sanitize()
inc/_at/ListingSections.php

ListingViews ListingViews.php​

PPT listing analytics — records a "hit" every time a single listing page is viewed, and serves that data back to the listing owner as a graph in the member area (/account ▸ My listings ▸ the analytics icon). Each view stores the listing id, the timestamp (UTC), and — when the visitor is logged in — their user id + display name, so an owner can see who has been looking. Bots/crawlers are skipped so counts reflect real visitors. The owner (and admins) can read the analytics for a listing over the AJAX endpoint, which returns a daily series (for the chart), rolling-window totals (7/30/60/90 days) and a list of recent named viewers. Storage: a custom table {prefix}ppt_listing_views (dbDelta on init).

API
register()table()install()maybeRecord()total()countSince()series()recentViewers()ajaxData()
inc/_at/ListingViews.php

Media Media.php​

Listing images — the single, WordPress-native resolver for the PPT image system. A listing's photos are its WP featured image (primary) plus any image attachments parented to it (the gallery). No legacy ?imgid refs, no image-URL meta strings — everything flows through the media library.

API
primary()gallery()videos()media()counts()
inc/_at/Media.php

Reviews Reviews.php​

Listing reviews — built on native WordPress comments so they moderate and store like any comment, but stamped with the comment type "review" (the identifier that distinguishes them from ordinary blog comments in the admin) and a 1–5 star rating saved as comment meta. Reviews are always enabled on the listing CPT. Rendered in the single-listing "Reviews" (summary + breakdown + cards) and "Add Review" (star input + comment form) sections.

API
register()open()stampType()saveRating()onCommentChange()onStatusChange()syncPostRating()count()all()stats()stars()renderSummary()renderList()renderForm()
inc/_at/Reviews.php

Roles Roles.php​

Bidder or Seller: who this member is on the auction profile. An auction site has two sides. A SELLER lists lots; a BIDDER bids on them. Sign-up asks which in its role step ("browse" / "list") and stores the answer in ppt_signup_role; this bridges that answer onto the type Account\AccountType understands (buy → CLIENT, sell → SOLO) and supplies the words — exactly the Micro Jobs pattern (Ppt_mj\Roles), cloned 2026-09-20 so the home-demo can offer a one-click "Bidder login" and "Seller login" and the hub can show the badge. Gated to the auction profile by Theme::boot()'s fork-gating (this is Ppt_at*).

API
register()profiles()typeForUser()typeCurrent()toType()options()shortLabel()typeOf()isBuyer()hidesSelling()accountBadge()
inc/_at/Roles.php

SearchPage SearchPage.php​

Server-rendered search / archive for the listing post type — the clean PPT rebuild of DT10's PPT\Custom\Search\SearchPage. Runs the normal WordPress main query (WP_Query) via official hooks (pre_get_posts + template_include) so it is SEO-friendly and every core filter applies. Contexts it owns: - keyword search (/?s=…) - the listing post-type archive (/listing/) - listing category / tag archives Filters (GET, all optional, combinable): s keyword tax-listing_category category term id price1 / price2 min / max price (numeric, price meta) sort featured | newest | oldest | rating | price_low | price_high | title paged pagination

API
register()shapeQuery()nearCoords()radiusKm()distanceFrom()distanceLabel()radiusClausesMain()radiusClauses()featuredOrderClauses()endingSoonOrderClauses()isListingContext()postType()isMapTakeover()categoryTax()terms()taxQueryFromRequest()listingTaxonomies()favOnly()favIds()hasActiveFilters()matchingIds()termCounts()priceMetaQuery()endMeta()
inc/_at/SearchPage.php

Settlement Settlement.php​

Auction settlement limit — an optional, site-wide cap (Settings ▸ Lots ▸ Auction Bidding) on the largest WINNING BID the site will take payment for online. When a won lot's item price is above the limit, the site does NOT charge its gateways; instead it hands the sale off, in one of two admin-chosen modes: - direct : the buyer and seller settle between themselves — the buyer is routed into the internal messaging thread with the seller (the lot's author). - vendor : a third-party the admin configures (a name + a URL the buyer is sent to, e.g. an escrow service). This is payment routing only — it never affects bidding (a lot may still be bid above the limit; only how the WON lot is settled changes). The limit is read live at every checkout/CTA render, so raising/lowering it re-routes existing pending orders the next time their winner looks. 0/empty limit = feature off. House commission (Ppt_at\Commission) is only taken on the online pay path, so no commission is collected on an off-site settlement — an inherent trade-off surfaced to the admin in the settings hint.

API
limit()enabled()mode()vendorName()vendorUrl()appliesTo()destinationFor()ctaLabel()buyerCommissionEnabled()sellerCommissionEnabled()commissionType()commissionRate()commissionApplies()commissionOn()commissionLabel()
inc/_at/Settlement.php

SingleListing SingleListing.php​

Single-listing page for the listing_type post type — the clean PPT rebuild of DT10's PPT\Custom\Single\SingleListing. Owns template_include for singular listings and renders its own token-styled template inside the normal main loop. No legacy $CORE / membership plumbing; standard WordPress access rules apply.

API
register()template()related()
inc/_at/SingleListing.php

TermMeta TermMeta.php​

Per-term IMAGE + ICON for the listing taxonomies. Adds two custom fields to the native WordPress term add/edit screens (Categories, Tags and any custom listing taxonomy): a media-library image picker and a swatch picker over the theme icon library. The values are stored as term meta and consumed by the live-category blocks (via Blocks\Support\Categories) so an admin can give each category a branded photo and icon instead of the auto-derived listing photo / fallback glyph. Admin-only UI; the read helpers (image()/imageId()/icon()) are safe to call anywhere. Taxonomies are resolved live from the listing post type, so new custom taxonomies get the fields automatically.

API
register()hookTaxonomies()taxonomies()imageId()image()icon()assets()addFields()editFields()save()
inc/_at/TermMeta.php

Uploads Uploads.php​

Listing media uploads — the AJAX backend for the Uppy uploader on the listing editor (replacing the WordPress media frame). Uppy's XHRUpload posts one file per request to ppt_listing_upload; each becomes a normal WordPress attachment (so Media::gallery()/Media::videos() and the single-listing template keep working). Files are left unattached (post_parent = 0) until the listing form is saved, which parents the final set (ListingEditor::save()). A companion ppt_listing_media_remove deletes a freshly uploaded, not-yet- saved attachment when the user removes it in the editor, so abandoned uploads don't pile up in the media library.

API
register()imageMimes()videoMimes()ajaxUpload()ajaxRemove()ajaxPoster()ajaxPersist()
inc/_at/Uploads.php