Four flat taxonomies attached to product (bsc_genre, bsc_mood,
bsc_content_warning, bsc_tag) reuse WordPress's native taxonomy archive
system for the "click a tag, see everything with it" browsing AO3 is known
for — no custom archive templates or query logic needed. Verified: all
four register correctly, render as clickable chips on the product page
(content warnings get a distinct notice instead of just another chip),
and the archive page + term count both work end-to-end with real test
data.
HardcoverAdapter + `wp bookstore sync-hardcover-tags` pull genre/mood/
content-warning/freeform tags from Hardcover's API to populate these.
This part is explicitly NOT verified against a live response — Hardcover's
API is in beta with informal docs, and there was no API token available
to confirm the exact query/response shape. Flagged clearly in the adapter
itself; needs a real token + introspection query before trusting the
field-parsing logic in production. ISBN-first-then-title/author matching
handles both real future ISBNs and the current Gutenberg-synthetic
catalog's fake ones.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Builds bookstore-core's first real business logic (design doc §02-§05,§07),
replacing the plugin stub with:
- Schema: bsc_work/edition/isbn/cover_variant/supplier_offer/member tables
via dbDelta, with a versioned upgrade path.
- GutenbergImporter: imports Project Gutenberg's live bulk catalog as
synthetic staging data. Deterministic checksum-valid ISBN-13s (there are
no real ISBNs in PG data) keep re-imports idempotent.
- SyntheticOfferGenerator: the GutenbergTestAdapter of §04 — realistic
condition/stock/price distribution with deliberate out-of-stock/stale/
discontinued cases for later exception-path testing.
- PricingEngine: the §05 margin formula, verified against the design
doc's own worked example ($6.00 + $3.99 -> $14.99 exactly).
- ProductSync: one WooCommerce product per Work, never per ISBN (§03),
idempotent (verified: re-sync of 2000 works produces 0 duplicates).
- BSC_Free_Shipping: a real WC_Shipping_Method (WooCommerce's built-in
Free Shipping only supports one static threshold, not membership-
conditional), verified through actual browser-session cart flows in
both directions, not just unit calls.
Found and fixed one real data-integrity bug while scale-testing: PG's
Authors field lists every contributor for anthology works, overflowing
primary_author's column — Work::insert() was failing silently (Catalog
insert methods never checked $wpdb->insert()'s return value), while the
following Edition/Isbn inserts for that same row went ahead anyway and
attached to whichever work_id was last successful. Fixed at the root:
inserts now throw on failure, the importer takes just the first author
(matching the column's actual semantic intent), and the import loop
catches per-row failures so one bad title can't abort a bulk run.
Verified end-to-end against a real 2000-title import: exact work/edition/
isbn/product count parity, no duplicates on re-run, real HTTP cart tests
for both shipping thresholds, live storefront search.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>