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>
64 lines
2.7 KiB
PHP
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);
|
|
}
|
|
}
|