Developer Reference
Technical reference for developers extending or integrating with Super Speedy AJAX Prices.
Last updated for plugin version 1.9.1.
Constants
One behaviour flag, defined in the main plugin file with an if (!defined(...)) guard so you can override it earlier (e.g. in wp-config.php or an mu-plugin).
SSAP_VERBOSE_LOGGING
- Default:
false - Logs the paths where the plugin declines to act rather than risk breaking the page: a theme or plugin throwing while an Add to Cart region is rendered, an unbalanced output buffer, a stock-asset primer failing. Without it those decisions are invisible.
- Writes to the WooCommerce log (WooCommerce → Status → Logs, source
super-speedy-ajax-prices), falling back toerror_log()where the WooCommerce logger is unavailable. - Leave it off in production — it is a diagnostic, and it logs on every affected render.
// wp-config.php
define( 'SSAP_VERBOSE_LOGGING', true );
AJAX request / response contract
If you want to consume the pricing endpoint directly (custom front end, headless probe, queueing layer) rather than relying on the bundled script, this is the contract.
Endpoint: admin-ajax.php, action ssap_get_prices (registered for both logged-in and logged-out visitors).
Request (POST):
| Field | Type | Notes |
|---|---|---|
action | string | ssap_get_prices |
product_ids | array | Product IDs. Coerced to int, de-duplicated, zero-filtered, and capped at ssap_max_products_per_request (default 200). |
single_regions | object | Optional. Map of product ID to the Add-to-Cart region types that product’s page rendered: "classic" (the woocommerce_single_product_summary priority window) and/or "block" (the woocommerce/add-to-cart-form block). Only these products get their single-product Add-to-Cart area rendered — it is the expensive part of the response. Values outside that pair are dropped. |
No nonce is sent, deliberately: a nonce cannot live in cached HTML without going stale. The endpoint is read-only, returns only published-product data, and resolves the visitor from their login cookie.
Response (wp_send_json_success):
{
"success": true,
"data": {
"prices": {
"123": { "price_html": "<span …>£10.00</span>", "is_variable": false }
},
"stock": {
"123": {
"availability_html": "<p class=\"stock in-stock\">5 in stock</p>",
"is_in_stock": true,
"is_purchasable": true,
"add_to_cart_html": "<a …>Add to cart</a>"
}
}
}
}
pricesis always present (keyed by product ID). Unknown / non-published / non-existent IDs are simply omitted.stockis present only when Refresh stock via AJAX is enabled. Adapter fields (bundled_items,components, etc.) appear inside each stock entry viassap_stock_data_for_product.- On no valid IDs the response is
wp_send_json_error({ message }).
No nonce, by design. A nonce is per-user and expires in roughly 12 to 24 hours, so one baked into full-page-cached markup is stale or belongs to another visitor and the request 403s. The endpoint takes none and resolves the visitor from their login cookie instead. It is safe to expose only because it returns public data, changes no state, gates to published products, and caps the batch — so keep it read-only.
Filters
ssap_max_products_per_request
Caps how many product IDs a single AJAX request to ssap_get_prices will process. Each ID in the request triggers a wc_get_product() load plus a price render (and, when stock refresh is enabled, a stock + Add-to-Cart template render), so the cap exists to stop one request from forcing thousands of those — both as an accidental-load safeguard on very large grids and as a deliberate-abuse / request-amplification safeguard on a public endpoint.
- Default:
200 - Applied: server-side, in
SSAP_Pricing::get_ajax_prices(), after the incoming IDs are sanitised (absint), de-duplicated, and zero-filtered. The first N IDs are kept; the rest are dropped for that request. - Return: an integer. The value is cast with
(int), so returning a numeric string is fine.
A normal shop or category page shows far fewer than 200 products, so most stores never need to touch this. Raise it only if you legitimately render more than 200 products in a single page (and therefore in a single batched refresh).
// Allow up to 500 products per AJAX refresh.
add_filter( 'ssap_max_products_per_request', function () {
return 500;
} );
You can also lower it to tighten the safeguard further:
add_filter( 'ssap_max_products_per_request', fn() => 60 );
Every ID in a request costs a wc_get_product() load plus a price render (and a stock + Add-to-Cart render when stock refresh is on). Batching all IDs into one request, and letting the bundled script re-init only newly-added placeholders, keeps that cost proportional to what actually changed rather than to catalogue size.
Note: Auto Infinite Scroll appends products in batches and re-initialises only the newly-added placeholders, so each refresh only ever requests the IDs that have not yet been loaded — this almost never approaches the cap regardless of total catalogue size.
ssap_stock_data_for_product
Filters the per-product stock payload returned by the AJAX endpoint (only present when Refresh stock via AJAX is enabled). This is the extension point the bundled Bundles and Composite adapters use to add their own per-product fields without the core plugin hard-coding knowledge of those product types (see Writing a Custom Product-Type Adapter).
- Parameters:
( array $data, WC_Product $product ) - Return: the (optionally augmented)
$dataarray.
Default $data keys:
| Key | Type | Description |
|---|---|---|
availability_html | string | WooCommerce’s rendered stock HTML (e.g. 5 in stock) |
is_in_stock | bool | $product->is_in_stock() |
is_purchasable | bool | $product->is_purchasable() |
add_to_cart_html | string | Rendered loop Add-to-Cart markup |
add_filter( 'ssap_stock_data_for_product', function ( $data, $product ) {
$data['my_custom_flag'] = (bool) get_post_meta( $product->get_id(), '_my_flag', true );
return $data;
}, 10, 2 );
ssap_single_region_start / ssap_single_region_end
The priorities on woocommerce_single_product_summary between which the single-product Add-to-Cart area is captured and re-rendered. Defaults 29 and 39, which bracket WooCommerce’s own Add to Cart (30) and leave product meta (40) outside. Widen them if your back-in-stock or pre-order plugin renders further down the summary.
// A notifier that hooks the summary at 45.
add_filter( 'ssap_single_region_end', function () {
return 46;
} );
ssap_prime_stock_asset_handles
Script/style handles to force onto a product page, on top of (or instead of) the automatic preload described in Live Stock Refresh. Use this when a plugin misbehaves if its form is rendered twice: switch the automatic preload off and name its handles here.
add_filter( 'ssap_prime_stock_asset_handles', function ( $handles, $product ) {
$handles[] = 'my-back-in-stock-notifier';
return $handles;
}, 10, 2 );
Published-only gate
The endpoint only ever returns data for products whose status is publish. Draft, pending, private, and scheduled (future) products are skipped — both when the price placeholder is inserted (replace_price_with_placeholder()) and again inside the AJAX handler (get_ajax_prices()). This prevents an unauthenticated caller from enumerating prices/stock for unpublished products. There is intentionally no filter to relax this — if you need AJAX pricing on a product, publish it.
The gate is enforced in two places — at placeholder insertion and again in the AJAX handler — so the two halves can never disagree, and there is deliberately no filter to relax it. If a product needs AJAX pricing, publish it; do not try to route unpublished prices through the public endpoint.
Actions
ssap_before_render_single_region / ssap_after_render_single_region
Fired either side of the server re-rendering a product’s Add-to-Cart area inside the refresh request. Both receive the WC_Product.
This request is not a page load: template_redirect never fires and is_product() is false, so anything your plugin normally does at page-render time to decide what renders there has to be replayed here. The commonest case is a notifier that removes WooCommerce’s Add to Cart while an item is sold out:
add_action( 'ssap_before_render_single_region', function ( $product ) {
if ( ! $product->is_in_stock() ) {
remove_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_add_to_cart', 30 );
}
} );
add_action( 'ssap_after_render_single_region', function () {
if ( ! has_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_add_to_cart' ) ) {
add_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_add_to_cart', 30 );
}
} );
Put anything you change back in ssap_after_render_single_region: one request can render more than one product.
JavaScript events
The front-end script fires these on document.body so other scripts can react:
| Event | Fired when | Args |
|---|---|---|
ssap_prices_updated | After prices have been swapped in | — |
ssap_stock_updated | After stock/Add-to-Cart have been swapped in | [stock] — the per-product stock map |
ssap_single_add_to_cart_replaced | After a single product page’s Add-to-Cart area has been replaced | [productId, stockData, element] |
Use ssap_single_add_to_cart_replaced for anything that binds to the Add-to-Cart markup itself rather than to document — a quantity stepper, a sticky add-to-cart bar, a notifier’s form handler. WooCommerce’s own variation form is re-initialised for you. Any inline <script> in the replaced markup is re-executed (innerHTML alone would not run it).
jQuery( document.body ).on( 'ssap_stock_updated', function ( e, stock ) {
console.log( 'Live stock for these products:', stock );
} );
Further reading
ssap_stock_data_for_product to add your own stock fields.
Comments