RECORDGOD/wp-bridge/includes/class-rg-cart.php
type-two 5ad4de1d2c feat(bridge): RecordGod WP bridge plugin (WowPlatter successor) + thumb on browse/release
Thin WordPress/Woo bridge — RecordGod owns catalog/stock/pricing/shipping; the plugin is a storefront
skin + checkout adapter over /shop:
- storefront: SSR /records (browse) + /release/{id} inside the theme, with title/meta/JSON-LD MusicAlbum
- on-the-fly Woo product: /?rg_add=<sku> mints a hidden WC_Product_Simple from /shop/item (the WowPlatter
  trick — 25k catalog, only sold items become Woo products)
- shipping: WC_Shipping_Method quoting /shop/shipping/quote by cart item count (AusPost flat rate)
- orders: order_status_completed -> POST /shop/woo-order (X-Bridge-Key), idempotent, marks SKUs sold
- settings page: base URL + bridge key + store id
Backend: added thumb to /shop/browse + /shop/release so storefront pages have cover art.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 01:43:30 +10:00

64 lines
2.7 KiB
PHP

<?php
if (!defined('ABSPATH')) exit;
/**
* On-the-fly Woo products — the WowPlatter trick. RecordGod holds the 25k catalog; Woo only ever sees the
* ~handful of items someone actually buys. A Woo product is minted the moment a SKU is added to cart, looked
* up by SKU thereafter (never duplicated), and kept out of the Woo shop loop (catalog_visibility=hidden).
*/
class RG_Cart {
static function init() {
add_action('template_redirect', [__CLASS__, 'handle_add']);
}
/** Ensure a Woo product exists for $sku (creating it from /shop/item if absent). Returns product id or 0. */
static function ensure_product($sku) {
$id = wc_get_product_id_by_sku($sku);
if ($id) return $id;
$item = RG_API::get('/shop/item/' . rawurlencode($sku), [], 0);
if (!$item || empty($item['in_stock'])) return 0;
$p = new WC_Product_Simple();
$p->set_name(trim(($item['artist'] ? $item['artist'] . ' — ' : '') . $item['title']));
$p->set_sku($sku);
$p->set_regular_price((string) $item['price']);
$p->set_price((string) $item['price']);
$p->set_catalog_visibility('hidden'); // never floods the Woo shop loop
$p->set_manage_stock(true);
$p->set_stock_quantity(1); // single physical copy
$p->set_sold_individually(true);
$p->set_weight('0.28'); // 230g record + 50g packaging (Woo fallback; real quote is RG_Shipping)
if (!empty($item['release_id'])) $p->update_meta_data('_rg_release_id', $item['release_id']);
$id = $p->save();
if ($id && !empty($item['thumb'])) self::attach_thumb($id, $item['thumb']);
return $id;
}
/** GET ?rg_add=<sku> → mint product, add to cart, bounce to the cart page. */
static function handle_add() {
if (empty($_GET['rg_add'])) return;
$sku = sanitize_text_field(wp_unslash($_GET['rg_add']));
$id = self::ensure_product($sku);
if ($id) {
WC()->cart->add_to_cart($id, 1);
wp_safe_redirect(wc_get_cart_url());
} else {
wc_add_notice('Sorry, that record has just sold.', 'error');
wp_safe_redirect(home_url('/records'));
}
exit;
}
/** Sideload the Discogs thumb as the product image (once). */
static function attach_thumb($product_id, $url) {
require_once ABSPATH . 'wp-admin/includes/media.php';
require_once ABSPATH . 'wp-admin/includes/file.php';
require_once ABSPATH . 'wp-admin/includes/image.php';
$att = media_sideload_image($url, $product_id, null, 'id');
if (!is_wp_error($att)) set_post_thumbnail($product_id, $att);
}
}