Developers

Developer Reference

Published · Last updated

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 to error_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):

FieldTypeNotes
actionstringssap_get_prices
product_idsarrayProduct IDs. Coerced to int, de-duplicated, zero-filtered, and capped at ssap_max_products_per_request (default 200).
single_regionsobjectOptional. 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>"
      }
    }
  }
}
  • prices is always present (keyed by product ID). Unknown / non-published / non-existent IDs are simply omitted.
  • stock is present only when Refresh stock via AJAX is enabled. Adapter fields (bundled_items, components, etc.) appear inside each stock entry via ssap_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 );
Performance Tip

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) $data array.

Default $data keys:

KeyTypeDescription
availability_htmlstringWooCommerce’s rendered stock HTML (e.g. 5 in stock)
is_in_stockbool$product->is_in_stock()
is_purchasablebool$product->is_purchasable()
add_to_cart_htmlstringRendered 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.

Best practice

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:

EventFired whenArgs
ssap_prices_updatedAfter prices have been swapped in—
ssap_stock_updatedAfter stock/Add-to-Cart have been swapped in[stock] — the per-product stock map
ssap_single_add_to_cart_replacedAfter 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

a worked example of calling the endpoint contract above from your own front end.
use ssap_stock_data_for_product to add your own stock fields.
the CSS classes and JS events on the front-end side of these hooks.
how these constants, filters, and events fit into the whole runtime.

Comments

▲
▼
1/1