QR Coupon

Developer docs

QR Coupon is built to be extended. It uses WooCommerce’s own cart and coupon APIs, exposes a read-only REST namespace, and fires actions and filters at every meaningful step. There are no external services — QR codes render client-side, and the only network dependency is Freemius for licensing. This page covers the public surface for v1.0.0.

The scan URL

Every QR encodes a plain URL on your store. When scanned, it’s intercepted on template_redirect, the product (or variation) is added to the cart, the coupon is applied, and the customer lands on the cart — already discounted.

https://your-store.com/?qrcw=1&p={product_id}[&v={variation_id}][&c={coupon_code}]
  • p — product ID (required).
  • v — variation ID (optional; for a specific size/colour).
  • c — coupon code (optional; omit for a plain add-to-cart).

REST API

Namespace qrcw/v1, read-only. Both routes require the edit_products capability. Writes are handled by admin-AJAX, not REST. Pro adds no REST endpoints — its analytics, campaign and conversion data live in the admin (AJAX + admin pages), so the two routes below are the complete REST surface.

EndpointMethodPurpose
/wp-json/qrcw/v1/urlGETBuild a scan URL from product_id (plus optional coupon, variation_id).
/wp-json/qrcw/v1/products/{id}GETList saved QR records for a product — scan counts and image URLs included.

Action hooks

Hooks marked Pro only fire when the Pro add-on is active — everything else ships in the free plugin.

HookFires whenArguments
qrcw_cart_taggeda scan tags the cart$attachment_id, $product_id, $coupon_code, $scan_id
qrcw_scan_recordeda scan row is written$args, $scan_id
qrcw_conversion_linked Proa scan is linked to an order$scan_id, $order_id
qrcw_conversion_updated Proa linked order changes$order_id
qrcw_delete_qra QR is removed$product_id, $attachment_id
qrcw_product_deleteda product is removed$product_id
qrcw_campaign_deleted Proa campaign is deleted$campaign_id, $delete_codes
qrcw_all_campaigns_deleted Proevery campaign is bulk-deleted$delete_codes
qrcw_purge_dataall plugin data is purged
qrcw_register_submenusthe admin menu is built (Pro adds menus)
qrcw_fs_loadedFreemius has finished loading (safe to call qrcw_fs())

Filter hooks

HookChangesArguments
qrcw_intercept_scanreturn true to claim a scan and skip the default add-to-cart flowfalse
qrcw_client_ipoverride the resolved IP before it’s hashed$raw_ip
qrcw_settings_defaultsdefault settings$defaults
qrcw_sanitize_settingssanitise settings on save$clean, $input
qrcw_sanitize_qr_designsanitise a QR design payloadarray(), $design_raw
qrcw_get_product_codesprovide saved codes for a productarray(), $product_id
qrcw_admin_js_datathe admin JS localisation payload$data
qrcw_codes_table_columns / _records / _column_htmlextend the All QR Codes tablecolumns / records / '', $item, $column
qrcw_clean_orphan_media / qrcw_clean_deleted_entitiesrow count from the data-cleanup tools$count

Example — append a column to the All QR Codes admin table:

add_filter( 'qrcw_codes_table_columns', function ( $columns ) {
    $columns['campaign'] = __( 'Campaign', 'your-textdomain' );
    return $columns;
} );

Admin AJAX & JavaScript

  • Admin AJAX: ~22 wp_ajax_qrcw_* actions handle all writes (generation, saving, deletion). They’re nonce-protected with qrcw_admin (the purge action uses qrcw_purge).
  • JS globals: window.qrcwRender builds the QR config and renders to canvas; qrcwRender.readPreviewDesign() reads the live design; confirmDialog() drives confirmations.
  • No shortcodes, no WP-CLI — the public surface is REST (read) + admin-AJAX (write).

Data & privacy

QR Coupon stores its data in four custom tables — qrcw_codes, qrcw_scans, qrcw_campaigns, and (Pro) qrcw_conversions — dropped on uninstall. It’s privacy-respecting by design:

  • QR codes are generated in the browser — nothing is sent to a third-party service.
  • Scan IPs are stored as an HMAC-SHA256 hash, never in the clear (override the source IP with qrcw_client_ip).
  • It implements the WordPress Privacy API exporters and erasers; conversions are anonymised to preserve aggregate revenue figures.

Building an integration and need a hook that isn’t here? These are the stable, documented entry points for v1.0.0 — open an issue on the plugin’s WordPress.org support forum and we’ll point you at the right one.