Files
bookstore/wp-content/plugins/bookstore-core
twooey 05e97b53f6 Harden sync_all() for future live-site use: per-row savepoints, scoped cache invalidation
Ahead of running this against a live site (not just staging bulk-imports),
addressed the two risks that only matter under concurrent traffic:

- One bad product no longer wastes a whole batch: each product save is
  wrapped in its own SAVEPOINT within the batch transaction, so a failure
  rolls back just that row (counted in the new failed[] result, surfaced
  via WP_CLI::warning like import-gutenberg already does) instead of
  discarding up to 200 already-good rows. Verified SAVEPOINT/ROLLBACK TO
  SAVEPOINT actually works on this MariaDB instance via a direct $wpdb test
  before relying on it.

- Cache invalidation suspension is now scoped per-batch instead of the
  whole run, with clean_post_cache() called explicitly per product once
  each batch commits, replacing the single end-of-run wp_cache_flush().
  This site runs a shared Redis object cache across PHP-FPM workers, so a
  whole-run suspension + full flush would let a concurrent visitor see
  stale cached product data for the run's duration, and the flush itself
  would evict sessions and everything else site-wide. Scoping bounds
  staleness to one batch and targets only the products actually touched.

Also moved term resolution (term_exists()/wp_insert_term()) out of the
per-product savepoint entirely: warm_term_cache() now resolves every
distinct subject for a batch before its transaction opens, so a term
created for one product can never get silently rolled back by a *different*
product's savepoint failure while a stale term_id sits cached in memory
and gets attached to a later product (an orphaned term_relationships row,
checked for directly post-fix: 0 found).

Verified after: 2000-item sync still ~90s (savepoints add no measurable
overhead), 0 lookup-table mismatches, 0 term-count mismatches, 0 orphaned
term_relationships, idempotent re-run with 0 duplicates.
2026-08-27 15:26:37 -04:00
..