Dette er en demoshop til testformål. Ordrer vil ikke blive gennemført. Luk

Videre til indhold
  • Forside
  • Løsninger
    • Hjemmesider
    • Nyhedsbreve
    • Webshop
    • WordPress
  • Webalive plugin
    • WooCommerce produkt sortering
  • kontakt
  • Forside
  • Løsninger
    • Hjemmesider
    • Nyhedsbreve
    • Webshop
    • WordPress
  • Webalive plugin
    • WooCommerce produkt sortering
  • kontakt

© 2019

Webalive plugin

← Tilbage til alle plugins

Woo Webalive Remote Stock

Af WebAlive

Version 1.9.36 WP 5.8+ Testet 7.1 PHP 7.4+ Opdateret 2026-09-12

Beskrivelse

Woo Webalive Remote Stock lets a WooCommerce shop track and display stock levels that live at distributors / suppliers, alongside the shop's own local stock.

Ships with:

  • An adapter interface (WWRS_Source_Adapter) so any XML / JSON / REST / CSV feed can be plugged in without touching core.
  • A first built-in adapter for XML feeds with HTTP Basic auth.
  • An admin screen under WooCommerce → Remote stock to configure sources and trigger imports manually.
  • A read filter (wwrs_get_remote_stock) for themes and other plugins (including Webalive Stock Status) to render remote stock next to local stock.

Mapping to Woo products:

  • Simple product: matched by SKU == remote model.
  • Variation: matched either by the variation's own SKU, or by a per-variation "Remote option value id" bound to the supplier's option_values_id.
Ændringslog

1.9.36

  • Marked as tested with WordPress 7.1 and WooCommerce 11.1.0.

1.9.35

  • i18n: Refresh the translation template (.pot) so the source strings introduced in 1.9.32-1.9.34 are extractable by translators: Available in %d week / Available in %d weeks (parametric plural from 1.9.32) and Remote stock - awaiting delivery time (WWSS coordination text from 1.9.33-1.9.34). No code changes in this bump.

1.9.34

  • Broaden the WWSS availability-text override introduced in 1.9.33. Previously it only fired for products whose stock status was explicitly set to the WWSS remote_1week extra status. In practice most shops use the global WWSS labels for the built-in outofstock / onbackorder statuses (e.g. "Fjernlager 4-5 dage" as the Danish translation of the shop's available_on_backorder custom text), which meant the override had no effect. WWRS now replaces the availability text with Remote stock - awaiting delivery time for ANY locally-unavailable product where wwrs_get_remote_stock returns a non-empty availability field, regardless of the specific WWSS status key in play. The class is still preserved so existing WWSS colours / CSS keep rendering, and the WWRS orange badge underneath still shows the precise wait.

1.9.33

  • Frontend coordination with Woo Webalive Stock Status (WWSS): when a product is manually set to the WWSS remote_1week label ("Remote stock - 4-5 days" / "Fjernlager 4-5 dage") but the supplier XML says the real wait is longer (e.g. <availability>Available in 8 weeks</availability>), WWRS now hooks woocommerce_get_availability at priority 20 and replaces the misleading WWSS text with the generic Remote stock - awaiting delivery time. The in-stock CSS class is preserved so the green colour and existing WWSS styling are unchanged. The exact remaining wait is still shown in the WWRS orange availability badge below. Only fires when the product's stock status is remote_1week AND wwrs_get_remote_stock returns a non-empty availability field.

1.9.32

  • Availability phrase i18n is now parametric. Instead of registering every Available in 1 week, Available in 2 weeks, ... Available in 16 weeks as separate strings the frontend badge now detects the Available in <N> week(s) pattern at display time and formats it through _n( 'Available in %d week', 'Available in %d weeks', $n ). Only two source strings need translating (singular + plural) and any number of weeks the supplier ships — including new ones like 14 or 20 — automatically inherits the Danish wording. Fixed phrases (Special order, Back-order, Discontinued, On request, Out of stock) still go through the direct-lookup path via translate().

1.9.31

  • Extended the availability phrase i18n registration to cover longer lead times seen in tubs.parts / spafix.dk feeds: Available in 9 weeks up to Available in 16 weeks. Poedit "Update from source" now picks them up alongside the previous 1–8 week set.

1.9.30

  • Frontend remote-stock badge now falls back to the supplier <availability> text when the aggregated remote quantity is zero or negative. Example: an XML feed row with <stock>0</stock><availability>Available in 6 weeks</availability> used to hide the badge completely; the badge now renders the availability string instead, translated through the plugin's own text domain so Poedit can pick up common phrases (Available in 6 weeks, Available in 4 weeks, Available in 2 weeks, Back-order, On request, Discontinued). StockApi::get_remote_stock() now exposes availability on each returned row so themes / consumers can render it themselves via the wwrs_get_remote_stock filter.

1.9.29

  • Two related fixes for the enriched Mapping-table title and the supplier preview modal.
  • title_for() now prefers the on-page <h1> element over the JSON-LD name field — the JSON-LD name on Zoey / Magento shops (tubs.parts, spafix.dk) often carries just a short model reference (e.g. Tourbillon Rotary) while the <h1> carries the full merchandising title (LVJ 3" jet - Tourbillon Rotary). Extraction order: <h1> → JSON-LD name → microdata name itemprop → HTML <title> → raw payload fallback.
  • preview_for() cache-hit detection no longer treats a supplier_item row filled by the light-weight title-only cron (SupplierItemRepository::set_title()) as a complete preview. Cache is now served only when the row also carries an image or a description — both signals that a full preview_for() scrape actually ran. Otherwise the modal falls through to a fresh fetch so images / descriptions / prices show up on first open without needing the Refresh button.

1.9.28

  • Create-draft flow is now a two-step process. Step 1 (wwrs_create_draft_product) fetches the supplier preview + runs the AI copy generation, then returns the AI title, an intermediate token and a list of supplier image URLs each with a suggested filename (product-title slug + index). The admin modal shows those images inline as an editable form so the operator can rename any file BEFORE it is sideloaded into the WP media library. Step 2 (wwrs_finalize_draft_product) receives the edited filenames + token, creates the WooCommerce product, sideloads each image using the operator-chosen basename and returns the edit URL as before. Intermediate state is stashed in a 15-minute transient. ImageSideloader::sideload() accepts an optional filename override; DraftBuilder::build() is split into prepare() + finalize() (build() remains as a convenience wrapper for callers that do not want the intermediate step).

1.9.27

  • Title enrichment log entries now appear under the actual source id (e.g. spa-plus-cover) in the Log tab's Source column instead of the generic wwrs_enrich_titles hook name. When a batch spans multiple sources, one log entry per source is emitted with that source's own processed / filled counts, matching how the daily-import log already labels rows.

1.9.26

  • Title-enrichment cron interval is now selectable under WWRS → Settings → Title enrichment interval: every 15 minutes / 30 minutes / hourly (default) / every 2 hours / every 6 hours / daily. Two custom intervals (wwrs_15min, wwrs_30min) are registered via cron_schedules; the scheduled event is automatically re-booked when the setting changes so the new cadence takes effect on the next admin page load.

1.9.25

  • The title-enrichment batch size (rows processed per hourly cron tick / per Enrich-titles click) is now configurable under WWRS → Settings. Default 30, min 1, max 500. Higher = fewer runs to enrich a whole feed at the cost of a longer per-run wall-time and more supplier traffic per burst.

1.9.24

  • Local CSV source adapter gains a new optional title_column config field (default Name) that names the header of the CSV column carrying the human-readable product title. best_title_for() now consults this value first for CSV rows before falling through to the generic Name / Title / ProductName candidates. Operators can point it at any header — e.g. Beskrivelse, Produktnavn, Long Name — to control what the background title enrichment stores.

1.9.23

  • New per-source Enrich titles button in the WWRS → Sources action column. Clicking it runs the same batch (30 rows, 400 ms throttled) that the hourly cron uses, but scoped to that single source — useful when a freshly added XML feed / CSV should be enriched immediately without waiting for the next WP-Cron tick. Backing helper: TitleEnrichment::run($source_id = null) now accepts an optional source id to filter the WHERE clause.

1.9.22

  • title_for() now uses the same JSON-LD / schema.org microdata extraction path that preview_for() already uses, before falling back to the HTML <title> element. The JSON-LD name field (e.g. "name": "Pump Aqua-Flo XP2e") is preferred because it carries the clean vendor-facing product name, whereas <title> on most B2B storefronts is padded with the shop name (Product | Shop) or is a generic "Product page". Extraction order: JSON-LD Product name → schema.org microdata name itemprop → HTML <title>. The already-existing raw-payload fallback added in 1.9.21 (Name / model) kicks in only when none of the three page extractors returns a value.

1.9.21

  • Background title enrichment falls back to the raw supplier row payload when the live HTML fetch produces no <title> — typical for Cloudflare-blocked suppliers, negative-cached transients or sources without a product_url_template. Fallback order: HTML <title> → Name / name / Title / title / ProductName from the imported row → supplier model value. Result: the enrichment log stops reporting "0 titles filled" for whole batches and the Mapping table gets a usable label for every row that carries either a scraped title OR a CSV / XML name field.

1.9.20

  • Importer::run() now writes an info log entry at the very start of every source import (Import started (adapter: xml_basic)), in addition to the existing entry written on completion. Makes it obvious in the WWRS log view whether an import that appears to hang has actually started, and pins the elapsed time of the fetch + parse step.

1.9.19

  • New background enrichment task wwrs_enrich_titles runs hourly via WP-Cron and slowly fetches the supplier product title for every stock row that does not yet have one — 30 items per run with a 400 ms delay between HTTP requests, so a full XML feed is gradually enriched without hammering the supplier or the local server. Titles are stored on the existing wp_wwrs_supplier_item.title column and shown as a new "Title" column in WWRS → Mapping. The mapping-page search field now also matches against the enriched supplier title, so operators can find a variant by typing a fragment of the human-readable name instead of an internal supplier item id or SKU.

1.9.18

  • row_to_preview() now always re-runs the CSV price transform (price_column, price_divisor, price_multiplier, price_surcharge, price_currency) at return time when the source has one configured, and overrides whatever was persisted in wp_wwrs_supplier_item.price. Same rationale as the always-re-resolve URL logic: operators tweak the CSV price columns / factors after rows were first scraped, and without recomputation the preview modal kept serving the stale pre-transform value (e.g. the raw 50.04 EUR from the CSV instead of (50.04 / 1000) * 1.4 + 50).

1.9.17

  • CSV price transform no longer silently substitutes default factors (divisor 1, multiplier 1, surcharge 0) when the operator leaves the corresponding source-config field blank. Each operation — divide, multiply, add — is now applied only when its variable is explicitly set to a non-empty numeric value; a blank field is a no-op instead of a hidden “multiply by 1”. Prevents surprises like an empty surcharge field still contributing to the final price whenever a rounding-format cycle runs.

1.9.16

  • The Danish AI-output spell-correction map is now an editable textarea under Remote Stock → Settings → AI, one wrong|correct per line (comments with # allowed). Ships with tykelse|tykkelse as the default; extend with tæt|tykt, betrek|betræk, or any other site-specific fix without editing plugin PHP. The wwrs_ai_spell_corrections filter still works and is merged on top of the textarea contents.

1.9.15

  • AI-generated Danish product copy is now run through a small post-processing spell-correction step before it is written to WooCommerce. Fixes the model's recurring habit of dropping a k when translating supplier attribute names — e.g. tykelse is rewritten to tykkelse (and Tykelse → Tykkelse) while preserving original case. Correction map is filterable via wwrs_ai_spell_corrections for operators who want to add more site-specific fixes without editing the system prompt on every run.

1.9.14

  • The XML source adapter (tubs.parts / spafix.dk feed format) now extracts the optional <availability> element for out-of-stock items — e.g. <availability>Available in 6 weeks</availability> — and stores it in the raw supplier row payload. When the raw-row preview fallback is used (Cloudflare-blocked / login-gated suppliers) an item whose remote stock is 0 or negative and that has an availability string now shows a prominent Availability: Available in 6 weeks line at the top of the description, in addition to being surfaced under a dedicated availability key on the preview so the AI draft builder / UI can render it as an out-of-stock badge instead of hiding the item.

1.9.13

  • When the live supplier fetch is blocked (Cloudflare 403 challenge page, HTTP error, empty body, or scraper returned no usable data) the preview now falls back to the raw supplier-row payload stored in wp_wwrs_stock.raw — the same JSON WWRS imported from the source adapter (CSV / XML / API). The row is rendered as a structured card: title = Name field, h1 = the supplier item id, description = a pretty-printed key/value list of every remaining column (skipping url / price / code), price / currency from the CSV price columns configured under Sources, plus a raw_fallback => true flag so the AI draft builder can detect it. image and images are left empty because a blocked page returns no image URLs. This lets the AI content generator produce a Danish draft product even when the supplier page cannot be scraped.

1.9.12

  • On cache-hit in preview_for() and title_for() the plugin now still performs a raw wp_remote_get() fetch and writes the exact raw HTML body to wp-content/uploads/wwrs-debug/{source}__{sha1(url)}.html (with a matching .json sidecar containing the HTTP status code, headers and body length). This means the debug folder always contains the raw response the server returned, not an interpreted snapshot of the cached row. The cached preview is still what the UI returns — the extra fetch is purely for the debug dump.

1.9.11

  • The wp-content/uploads/wwrs-debug/ folder is now also populated on the early-return paths of preview_for() and title_for(), not only when an HTTP fetch actually happens. Cache-hit returns write {source}__{sha1(url)}__cache-hit.json with the reason and a small snapshot of the row that was served from cache, and unresolved URLs write {source}__unresolved__{sha1(item)}.json explaining why url_for() produced nothing. This makes it possible to see WHY "No preview available" was returned even when no network fetch was performed.

1.9.10

  • AI draft products now prefer the supplier's model value (e.g. 01510-0042) as the WooCommerce SKU instead of the internal supplier item id (e.g. 2595). Lookup order for the new product SKU is: (1) model column of the WWRS stock row, (2) SKU scraped from the supplier product page (only when it differs from the numeric supplier item id), otherwise the SKU is left blank rather than falling back to the supplier item id.

1.9.9

  • Every supplier-page fetch is now dumped to disk under wp-content/uploads/wwrs-debug/ so you can inspect exactly what the server got back — response status, headers, body length and the raw HTML. Filename shape: {source_id}__{sha1(url)}.html (metadata sidecar: .json). Old files are overwritten on each fetch, so the folder never grows unbounded (one file per unique supplier URL). Use this to diagnose "No preview available" cases: if the dump shows a 200 OK with real product HTML, the extractor logic is the issue; if it shows a login page, Cloudflare challenge or a redirect, the site is gating anonymous access and CSV / manual fallback is required.

1.9.8

  • Supplier-page scraper now uses a realistic Chrome-desktop User-Agent and 15-second timeout for both title_for and preview_for fetches. Cloudflare-fronted / Zoey / legacy Magento shops (spa-plus.eu, tubs.parts and similar) frequently reject the previous bot-style UA with an empty body or a 403 challenge, which surfaced in the WWRS UI as "No preview available". Live supplier pages that a normal browser can read should now respond correctly.

1.9.7

  • CSV price fallback (introduced in 1.9.6) can now be transformed on the fly with three new optional config fields on the CSV adapter: Price divisor (e.g. 10000 when the CSV stores fixed-point integers such as 1234500 = 123.45), Price multiplier (markup factor, e.g. 1.4 for +40 %), and Price surcharge (fixed amount in the same currency added last, e.g. 100 for shipping / handling). Formula: (raw / divisor) * multiplier + surcharge. Divisor defaults to 1, multiplier defaults to 1, surcharge defaults to 0 (all disabled). Both comma and dot decimal separators accepted.

1.9.6

  • Local CSV source can now supply the product price when the supplier page hides it behind a login (e.g. spa-plus.eu's B2B webshop). Two new config fields on the CSV adapter: Price column (CSV header name, e.g. Price) and Price currency (ISO code such as EUR). When the live-page scraper cannot find a price, the preview falls back to the CSV row value automatically; PriceConverter then handles conversion into shop currency as usual. Leave both fields blank to disable the fallback.

1.9.5

  • Image scraper now also picks up <img class="gallery-image"> (Zoey / spa-plus.eu product image gallery). Added alongside the existing main_image / sub_image fallbacks so multi-image galleries render properly when JSON-LD / microdata do not enumerate every gallery frame.

1.9.4

  • Scraper now understands schema.org microdata (HTML itemscope / itemprop attributes) in addition to JSON-LD. Sites built on Zoey / Magento / other legacy stacks such as spa-plus.eu embed the same schema.org Product data as microdata rather than a <script type="application/ld+json"> block; auto extraction now tries JSON-LD first, then microdata, then falls back to class-based heuristics. Extracted microdata fields (name, sku, brand, image, description) feed the preview the same way JSON-LD does. No config change needed.

1.9.3

  • JSON-LD extraction is now a per-source setting via a new Extraction mode dropdown: auto (default — use JSON-LD when present, fall through to / class heuristics otherwise), json_ld (JSON-LD only, empty preview when absent), heuristic (skip JSON-LD entirely and rely on class-based selectors). Lets a Zoey-based supplier such as spa-plus.eu — which ships schema.org data as HTML microdata (itemprop=”…”) rather than a <script type=”application/ld+json”> block — use heuristic while tubs.parts-style sources stay on auto.

1.9.2

  • Fix: Supplier preview modal showed a stale, unresolved "Attempted URL" (fx just cover-round-176-cm-diameter without the https://spa-plus.eu/ prefix) after the operator updated product_url_template or strip_tokens on the source config. Root cause: SupplierPageTitle::row_to_preview() — the fast-path used on every fresh cache hit — returned (string) ( $row['url'] ?? '' ) directly from the cached wp_wwrs_supplier_item.url column, which was populated at the time of the FIRST scrape and never re-resolved on subsequent opens. Cached rows produced before the URL template was configured (or produced with strip_tokens missing) therefore kept serving the old broken URL, and because the value was a bare slug the browser resolved the modal's <a href> against wp-admin/ — producing links like https://<site>/wp-admin/cover-round-176-cm-diameter instead of https://spa-plus.eu/cover-round-176-cm-diameter. row_to_preview() now re-runs url_for() on every call so template + strip_tokens changes are honoured immediately (falls back to the cached column only when url_for() returns empty).

1.9.1

  • Strip tokens for the CSV source's product URL template are now managed in a dedicated Strip tokens textarea (one token per line) on the source config, instead of being crammed into the template as |strip:token1,token2,…. The template stays clean (https://spa-plus.eu/{URL}), and strip tokens from the textarea are auto-applied to every unfiltered {Column} placeholder. Inline |strip: still works when a specific placeholder needs a different list.

1.9.0

  • Rolled-up feature release for the CSV pipeline shipped incrementally through 1.8.24–1.8.26: new Local CSV file source adapter, product_url_template field surfaced in the CSV adapter's Add form, and template filters (|slug, |strip:token1,token2,..., |raw) for building the live supplier URL from CSV columns.
  • Supplier preview modal now surfaces the attempted supplier URL in the empty-preview state, so operators can spot template mistakes (wrong slug, missing base URL, unresolved {Column} placeholder) at a glance instead of guessing.
  • Documented recommended token list for Spa-Plus: -charcoal, -walnut, -vinyl, -weathershield, -grey, -mahogany. Order doesn't matter — the filter removes each literal substring, then collapses - runs and trims trailing -, so all four Spa-Plus colour variants collapse down to the same base URL.

1.8.26

  • Product URL template gets a new |strip:token1,token2,... filter. Removes any of the given literal substrings from the value before URL-encoding, then collapses repeat - and trims leading/trailing -. Useful for CSV feeds where the URL column encodes colour / material variants that don't exist on the live catalogue page — e.g. {URL|strip:-charcoal-vinyl,-walnut-vinyl,-weathershield-grey,-weathershield-mahogany} collapses cover-79-79-r5-charcoal-vinyl down to cover-79-79-r5.

1.8.25

  • Product URL template now supports column placeholders and a |slug filter in addition to the existing {id} placeholder. Lets a CSV source (e.g. Spa-Plus) build the supplier product URL from any column: https://spa-plus.eu/{URL} uses the CSV's URL slug column verbatim, while https://spa-plus.eu/{Name|slug} derives it from the human-readable name by stripping every (…) group and turning spaces into dashes.
  • The product_url_template field is now surfaced in the Local CSV file source's Add form.

1.8.24

  • New adapter: Local CSV file (local_csv). Reads a CSV that a supplier drops daily into wp-content/uploads/wwrs-supplier/{sub-dir}/{filename}.csv (typical setup: SFTP delivery to a per-supplier folder). Configurable ID column, quantity column and delimiter — defaults suit the Spa-Plus stocklist (Code / Stock_Qty, comma-separated). Every non-ID/non-qty column is preserved on the supplier item row (raw field) so future adapters can surface title, dimensions, price, colour etc. in the preview.

1.8.23

  • Settings → Default stock behaviour gets a new Stock quantity field (integer, min 0, default 1). Applied to every new draft product via WC_Product::set_stock_quantity(). Takes effect only when Manage stock is enabled.

1.8.22

  • New: Product thumbnail column in the Mapping tab. For linked rows, the row now shows a 40x40 thumb of the WooCommerce product's featured image between the Supplier item and Variation columns. Clicking the thumb opens a gallery modal that displays every image on the product card — featured image first, then all gallery images — with a main viewer + clickable thumbstrip and left/right arrow-key navigation. Image URLs are emitted as a JSON array in data-wwrs-images on the thumb wrapper (server renders full-size URLs via wp_get_attachment_image_url( $id, 'large' )), so opening the modal requires no extra AJAX round-trip. Unlinked rows show a small placeholder square so the column is visually consistent.

1.8.21

  • Removed the Skip image dimensions setting introduced in 1.8.17. The dimension-blocking approach was the wrong direction — JSON-LD-first extraction (1.8.19) makes it unnecessary. All associated code removed: setting field in Settings, POST handler entry, Settings::DEFAULT_AI_SKIP_IMAGE_DIMENSIONS constant, ImageSideloader::parse_blocked_dimensions(), the dimension arm of the intermediate_image_sizes_advanced filter, and the post-download check in SupplierImageCache::mirror(). The stored option value is left in place harmlessly on existing installs.

1.8.20

  • Self-healing preview cache: on every preview_for() cache-hit, WWRS now verifies that the image and images URLs stored in wp_wwrs_supplier_item still point at real files on disk in wwrs-cache. If any local file is missing (folder purged, admin cleanup, filesystem drift), the row is treated as stale, a fresh scrape runs and the DB row + images are re-mirrored. Prevents the modal (and any product draft built from cached data) from showing broken supplier images.

1.8.19

  • Scraper now trusts schema.org Product JSON-LD as the authoritative source: when a supplier page ships a <script type="application/ld+json">Product</script> with image, description, sku, brand and offers.price, WWRS uses ONLY those values — no <img> / main_image / "Click to enlarge" heuristics run. Fixes cases where tubs.parts-style pages served a thumbnail + a full image both matching supplier styling, and we picked up the wrong sizes.
  • Blanket dimension-blocking from 1.8.17 / 1.8.18 was the wrong approach and is no longer applied by default: ai_skip_image_dimensions defaults to empty. The setting remains available as an optional escape hatch for sites without JSON-LD.

1.8.18

  • SupplierImageCache::mirror() now checks the downloaded file's actual pixel dimensions against the operator-configured Skip image dimensions blocklist. If the fetched file matches (e.g. 600x480), it's deleted from wwrs-cache and the mirror falls back to the remote URL. Stops thumbnail-sized supplier images from ever landing in the local cache directory. Logged as skipped-by-dimensions: 600x480 in Remote stock → Log.

1.8.17

  • The 1.8.11 filter only suppressed intermediate image sizes by key name — so a WooCommerce core size like woocommerce_single configured to 600x480 in Customize → WooCommerce → Product Images still slipped through. Filter now also drops any registered size whose dimensions match a user-configurable blocklist. Defaults to 600x480,640x480 — the two the shop theme most commonly produces.
  • New Settings field Skip image dimensions (Settings → AI product generation) so operators can add / remove blocked dimensions without touching code.

1.8.16

  • SupplierImageCache::mirror() had NINE silent early-return branches. When any of them fired, wwrs-cache stayed empty and the modal fell back to hot-linking supplier URLs, with no diagnostic anywhere. Every failure branch now logs to WWRS → Remote stock → Log with reason (unsupported extension, upload_dir error, mkdir failed, HTTP transport error, non-2xx status, empty body, non-image content-type, write failed, etc.).
  • HTTP timeout bumped from 5s to 15s for supplier image mirroring — many supplier CDNs cold-start slowly and 5s occasionally hit.

1.8.15

  • Yoast writes now go through Yoast's own WPSEO_Meta::set_value() API when available, which applies wp_slash() and honours per-key sanitisers registered by Yoast Premium (previous direct update_post_meta() writes could be rejected by Yoast Premium's sanitize callback for keyphrase synonyms). Falls back to update_post_meta() when Yoast is not active.
  • AI Log now dumps every _yoast_wpseo_* postmeta key + value for the created product immediately after write, so any additional key Yoast Premium uses for synonyms shows up in one glance.

1.8.14

  • Settings → AI product generation now exposes default stock behaviour for new drafts: manage stock (yes/no), initial stock status (in stock / out of stock / on backorder), allow backorders (no / notify customer / yes) and sold individually. Defaults suit a remote-stock workflow: manage stock = no, stock status = out of stock, backorders = notify. All four are applied to the WC_Product_Simple before it's saved.

1.8.13

  • The "Extra info" modal now includes a Product categories multi-select showing every WooCommerce product_cat term (indented by depth). Selected categories are assigned to the draft product on creation — no manual re-tagging in the editor.

1.8.12

  • Yoast synonym write: increased the internal cap from 5 to 20 entries so the full comma-separated list produced by the AI actually reaches the metabox, and switched the write to plain UTF-8 (no wp_kses / no sanitize) so brand/model tokens with spaces are preserved verbatim.
  • All Yoast postmeta writes for the generated draft (_yoast_wpseo_focuskw, _yoast_wpseo_keyphrase_synonyms, _yoast_wpseo_title, _yoast_wpseo_metadesc) are now captured in the AI Log entry — lets you verify at a glance whether the field was written and with which value, so you can distinguish a WWRS write bug from a Yoast metabox display / caching issue.

1.8.11

  • Suppress theme-registered intermediate image sizes (e.g. 600x480 / 640x480 / product_thumbnail from the shop theme) for images sideloaded by WWRS. Only the WordPress core sizes (thumbnail, medium, medium_large, large) and WooCommerce's three product-image sizes (woocommerce_thumbnail, woocommerce_single, woocommerce_gallery_thumbnail) are generated. Uploads made through the normal Media Library UI are unaffected — the filter only fires while an image is being sideloaded by DraftBuilder.

1.8.10

  • Critical fix: AI prompt builder called wp_strip_all_tags() on already-plain-text supplier data, which stripped everything from the first literal < to end-of-string. Symptom: supplier descriptions containing a value like Noise level: <69.5 DBA (perfectly valid in the preview modal) were truncated at exactly that point when sent to OpenAI, silently dropping later sections such as Dimensions, Connections, Cable and plug, Warranty and Part numbers. The AI could not include what it never saw. Prompt builder now only normalises whitespace — tag stripping is done once, in the scraper, before the text is stored.

1.8.9

  • Fix: supplier description scraper truncated at the first inner </div> because it used a non-greedy regex that cannot track nested block-level tags. Symptoms: text ended mid-sentence (e.g. "Noise level :" with no value), and later sections like Dimensions and Connections were silently dropped. Rewritten to use DOMDocument, which respects HTML tag nesting properly.
  • Fix: m³/h and similar UTF-8 characters were mangled into m�/h because character encoding was not enforced on the raw feed body. Description is now normalised to UTF-8 with mb_convert_encoding fallback + auto-detect for Windows-1252 supplier pages.

1.8.8

  • Fix: the AI Log tab added in 1.8.6 was registered in the tab constant but never rendered in the tab bar because render_tabs() had its own hardcoded label list that missed ai_log. Tab is now visible under WWRS → Remote stock → AI Log.

1.8.7

  • New "Extra info" step before AI generation: clicking Create draft product now opens a small form modal where you can supply information the supplier data doesn't contain (alternative part numbers, compatible spa brands/models, technical notes, wholesaler references). Any text entered is passed to the AI as an authoritative local_knowledge block — the model must integrate it and NEVER contradict it. Leave every field blank to skip and generate straight from supplier data.

1.8.6

  • New AI Log tab under WWRS → Remote stock captures the last 20 AI product-generation requests: the exact supplier payload sent to OpenAI, the raw JSON response, model + token counts and timing. Makes it easy to diagnose whether missing content (Dimensions, versions, tech specs, etc.) is a scraper problem (data was never fetched) or a model problem (data was fetched but skipped).
  • OpenAI request now explicitly sets max_tokens = 4096 so very rich long descriptions don't get silently truncated.
  • Switched OpenAI Chat Completions to strict JSON schema (response_format: json_schema with strict: true). Fixes the previous problem where the mini model would occasionally leak title: / Kort: field markers into the long_description body, or return a blank yoast_synonyms. All seven fields are now guaranteed present and correctly scoped in the response.
  • Available on gpt-4o-mini (2024-07-18 and newer) and all gpt-4o variants. Older gpt-3.5-* models are NOT supported by the new schema mode — stick to the 4o family.

1.8.5

  • "Create draft product" now opens the new product editor in a new browser tab instead of navigating away from the supplier item list, so the user can continue drafting the next item without losing context. Uses the synchronous window.open() pattern so popup blockers don't intervene.

1.8.4

  • Mappings are now automatically removed when a product is permanently deleted (before_delete_post), so orphan rows can't accumulate in wp_wwrs_mapping.
  • "Create draft product" dedupe check now ignores trashed products: if the mapped Woo product is in the trash (or already fully deleted), the stale mapping is cleaned up on the spot and a fresh draft can be created — no need to hand-empty the trash first.
  • Both cleanup paths also strip the _wwrs_supplier_link postmeta mirror on the product and any of its variations.

1.8.3

  • Yoast keyphrase synonyms are now generated by the AI and written to postmeta _yoast_wpseo_keyphrase_synonyms — Yoast's "Keyphrase synonyms" field is populated with 3-5 alternative search phrases (brand/model variations, common Danish spellings, English/Danish mix).
  • Focus keyphrase rule loosened from "2–4 words" to "main product name + model, typically close to the product title" — matches manual copywriting practice.

1.8.2

  • Sideloaded product images now use human-readable filenames based on the product title with a counter (spa-filter-poolpartner-1.jpg, -2.jpg, ...) instead of the supplier's hash filename.
  • Aspect-ratio safe padding to 1000x1000 JPG: non-square source images (e.g. 800x1000) are now scaled to fit inside 1000x1000 preserving aspect ratio, then centered on a 1000x1000 canvas padded with the source's own background color (sampled from the top-left pixel). Prevents the previous behavior of cropping content off tall/wide product shots.

1.8.1

  • OpenAI API key can now be provided via a PHP constant defined in wp-config.php, avoiding a duplicate copy in the database. Checked in order: WWRS_OPENAI_API_KEY (WWRS-native), then WOO_AI_SEARCH_OPENAI_API_KEY (shared with the woo-ai-search plugin). When either constant is defined and non-empty the Settings UI locks the API-key field and shows which constant is in use.

1.8.0

  • AI-assisted draft product creation. New "Create draft product" button in the supplier preview modal generates a WooCommerce product draft from a supplier item: OpenAI Chat Completions writes the Danish title, short description, long description, Yoast focus keyword, Yoast meta description and Yoast SEO title in one call. Supplier images are sideloaded to the Media Library, resized to 1000x1000 JPG, and set as featured image + gallery — the existing dFactory Image Watermark plugin picks them up automatically on upload.
  • New Settings section AI product generation with editable system prompt (defaults to a Danish product-copy prompt), API key, model (default gpt-4o-mini), image count cap (default 5) and markup factor (default 1.0 = supplier gross unchanged; set > 1 to apply a margin).
  • Duplicate protection: if the supplier item is already mapped to a Woo product, the button is disabled and links to the existing product instead.
  • Draft products are auto-mapped to the supplier item via _wwrs_supplier_link postmeta, so WWRS stock badge starts working immediately.

1.7.0

  • Scheduled daily import via WP-Cron. When enabled in Settings the plugin runs every configured source once a day at the chosen hour (site timezone, default 04:00). Uses the same code path as the manual "Import now" button, so imports remain atomic per source (delete + insert in a transaction).
  • New settings section Automatic import with enable checkbox, hour-of-day picker (0–23), next-run readout and a Run all now admin button.
  • Cron event wwrs_daily_import is unscheduled automatically on plugin deactivation and uninstall.

1.6.16

  • Broader scrub for supplier text fields: on top of stripping 4-byte UTF-8 the plugin now (a) re-encodes any malformed UTF-8 byte sequences with the Unicode replacement character (via mb_convert_encoding UTF-8 -> UTF-8 with mb_substitute_character(0xFFFD)), and (b) removes C0 control characters other than tab / LF / CR (NULL bytes, backspace, form feed, escape). These are the values MySQL rejects with the generic "field failed" error even on tables with correct charsets.

1.6.15

  • Fixed WordPress DB insert failure when the extracted supplier description contained 4-byte UTF-8 characters (emojis, rare CJK, some math symbols) and the shop's DB tables were still on the legacy 3-byte utf8 collation. title, h1, description, description_full are now pre-scrubbed of 4-byte codepoints (replaced with U+FFFD replacement) before insert/update, so 4-byte chars in supplier catalogues no longer crash the preview save.

1.6.14

  • Fixed off-by-one in SupplierItemRepository::upsert() INSERT / UPDATE format arrays (13 fields but 14 formats on INSERT, 11 fields but 12 formats on UPDATE). The extra %s was silently misaligning the placeholder mapping, so DB writes could fail on some rows.
  • Upsert now throws a RuntimeException when $wpdb->insert / $wpdb->update return false and includes $wpdb->last_error, so the AJAX endpoint surfaces the real DB error instead of a misleading "template-empty" message.

1.6.13

  • When preview_for() returns null, the AJAX error message now includes an explicit reason (source-not-found, empty-supplier-item-id, template-empty, etc.) with the actual source_id and template values inline, so it's obvious why the URL couldn't be resolved.

1.6.12

  • All AJAX endpoints now return HTTP 200 with {success:false,data:{message:...}} for handled errors (previously they used 400/403/404/500). Non-200 codes make jQuery's $.ajax skip .done() and jump straight to .fail(), which was swallowing our specific error messages and always showing the generic "Kunne ikke hente forhÃ¥ndsvisning". This is the standard WordPress AJAX contract.

1.6.11

  • AJAX preview endpoint wraps the extractor in try / catch and returns the exception's message (plus file / line for admins with WP_DEBUG on) instead of letting a fatal error surface as a generic "Kunne ikke hente forhÃ¥ndsvisning". Errors are also error_log'd so hosters can see them without hitting the browser again.

1.6.10

  • Fixed AJAX preview timing out ("Could not fetch preview.") on products with 3+ images. Image mirror timeout reduced from 15 s to 5 s and skipped image files are silently left as remote URLs. Also aborts image mirroring once the whole request has spent 25 s so the AJAX call always returns within PHP's default 30 s ceiling.

1.6.9

  • Fixed frontend badge position setting being ignored on single product pages. The woocommerce_get_stock_html filter was appending the badge to WooCommerce's <p class="stock"> element (which lives at the top of the summary) and the dedupe guard then blocked the position-controlled action hook. On single-product pages the filter is now skipped for the main product so the position setting is respected, and the badge is wrapped in a block-level <p class="wwrs-badge-remote-wrap"> so it takes its own line without pushing the add-to-cart form sideways.

1.6.8

  • Frontend badge placement is now configurable in Settings. Choices: Above price (priority 4), Below price (12), Above add-to-cart (25 — previous default), Below add-to-cart (35), In product meta (45).
  • Removed the debug <!-- wwrs ... summary: ... --> HTML comment from single product pages. Nothing traceable is emitted in production output any more.

1.6.7

  • Every mapping is now also written as a repeatable _wwrs_supplier_link postmeta on the Woo product / variation post. Value format: source_id|supplier_item_id|supplier_variation_key. Visible in wp-admin custom fields, WP All Export, wp-cli, and any code that queries products by supplier reference.
  • Delete / unlink also removes the matching postmeta value.
  • Upgrade path: existing rows in wp_wwrs_mapping (from earlier versions) are back-filled to postmeta on next admin_init.
  • Frontend badge now reads directly from postmeta first (fallback to mapping table), so a product linked via WP All Import (postmeta only) also fires the badge without touching the plugin admin.

1.6.6

  • Diagnostic HTML comment renamed the ambiguous qty field to remote_qty and added the product's SKU so it's easier to see whether an SKU fallback lookup should have matched a supplier model.

1.6.5

  • Badge trigger widened: any stock status other than instock counts as unavailable (previously onbackorder was silently accepted as available). So products on backorder / out-of-stock / unknown status now all get the badge when the shop has remote stock.
  • Detection also still fires on positive manage_stock with qty <= 0 (regardless of backorder flag).

1.6.4

  • Badge trigger no longer relies solely on WC_Product::is_in_stock(). That returns TRUE for products with _manage_stock = 'no' even when their explicit stock quantity is 0, which meant the badge never fired for shops that manage stock via the stock_status flag while a numeric quantity of 0 still lives on the product. New trigger: badge shows when EITHER is_in_stock() is false OR the product manages stock and get_stock_quantity() <= 0.
  • Debug HTML comment now includes stock_status, stock_qty and manage_stock so it's obvious what Woo believes about a product's local availability.

1.6.3

  • Frontend badge injects an HTML comment on single-product pages regardless of whether a badge is emitted, so you can inspect the source to see exactly why the badge did or did not render (in stock? remote qty? feature disabled? not mapped?).
  • Inline CSS gained a /* WWRS <version> */ marker so it's trivial to confirm the deployed version matches the code you expect.

1.6.2

  • Frontend badge now also renders via a direct woocommerce_single_product_summary action (priority 25) so it appears on single-product pages even when the theme skips the standard wc_get_stock_html output for out-of-stock products.
  • Same product won't render the badge twice: the filter path and the action path share a per-request "already-rendered" guard.
  • Frontend inline CSS is now enqueued on every non-admin page (small cost), so the badge always looks styled regardless of where WooCommerce injects the html.

1.6.1

  • Converted price now floors to the nearest whole unit of the target currency (e.g. 1699.53 → 1699.00) while still formatting with two decimals so amounts render consistently. Applies to same-currency VAT conversions too.
  • Fixed preview modal price row layout: label "Supplier" / "Your store" now sits on its own line above the value instead of colliding with the amount.

1.6.0

  • Frontend remote-stock badge: when a Woo product would otherwise render as "out of stock", WWRS now injects an orange badge with the total remote quantity (summed across every mapped supplier item). Text and colour are configurable in Settings. When the remote quantity is below the Only-threshold (default 5), the alternative wording (default Only %d in remote stock) is used to convey scarcity.
  • Rendering hooks: woocommerce_get_stock_html on single product + shop loop, so it appears wherever Woo would otherwise print "Out of stock".
  • Consumers can override via wwrs_stock_badge_html and wwrs_stock_badge_qty filters.
  • No effect on WWSS or other display plugins — the badge is standalone.

1.5.0

  • Full text description: preview now grabs the entire body copy from the supplier product page (<div class="product_info_description"> on tubs.parts, generic fallbacks otherwise), not just the short meta description.
  • Every product image: JSON-LD image array + .main_image + .sub_image are all collected, de-duplicated and mirrored to wp-content/uploads/wwrs-cache/. Modal renders the primary big image plus a horizontal thumbnail strip.
  • EUR → DKK currency conversion: preview shows both original supplier price and a converted target-currency price. Formula strips source VAT, converts via a configurable rate, then adds target VAT. Defaults: base DKK, base VAT 25 %, rate EUR = 7.45. Per-source source_vat_pct config field (default 20 for tubs).
  • New Settings tab on the Remote stock page: edit base currency, base VAT %, and currency rates in one place.
  • Schema bumped to 1.5.0 with new images (JSON) and description_full columns on wp_wwrs_supplier_item; the cache is truncated automatically on upgrade so every item re-fetches.

1.4.0

  • Dashboard header on the Remote stock page: shows total supplier items, linked, ignored, unmapped, and configured sources at a glance. Numbers are live counts from the DB.
  • Auto-link button on the Mapping tab: iterates every unmapped supplier stock row, runs the source's SKU transform (prefix strip + wildcard + ignore-separators + candidate regex), and creates a mapping when there is exactly one Woo SKU match. Ambiguous rows (multiple candidates) and rows with no candidate are skipped so nothing risky is auto-linked.
  • Auto-link is scoped by the current Mapping tab filters (source / status / search), so you can preview “unmapped” rows, then click Auto-link to sweep them.
  • Result summary after a run: linked / ambiguous / no candidates / already mapped.

1.3.0

  • Product edit page → Remote stock metabox is now a full two-way mapping manager:
    • Shows every explicit mapping currently linked to this product / variations (source, supplier item id, variation, live qty, unlink button).
    • Search-as-you-type widget queries the plugin's supplier item + stock tables so merchants can pick a supplier item to link straight from the product edit page. Matches on supplier_item_id, model, cached title and description.
    • Falls back to legacy "remote stock rows matched by SKU" section when no explicit mapping exists so nothing is hidden.
  • New AJAX endpoint wwrs_search_supplier_items (nonce + manage_woocommerce protected).
  • Modal image now loading="lazy" and hooked up to the mirrored local URL introduced in 1.2.15.

1.2.15

  • Supplier images are now mirrored to wp-content/uploads/wwrs-cache/ and served from your own domain. Tubs.parts (and many other shops) block hot-linking of images — embedding <img src="https://www.tubs.parts/..."> on your admin page returned nothing / a broken image. Mirroring bypasses this and also makes previews instant on repeat views.
  • Referer header is forwarded to the supplier so their hot-link protection accepts the fetch.
  • Only whitelisted image extensions (png / jpg / jpeg / gif / webp) are cached. Files are named {sha1(url)}.{ext} and served directly by the web server (no PHP wrapper).
  • Falls back to the remote URL if caching fails for any reason (permissions, disk full, ...).

1.2.14

  • Upgrade path: on schema bump to 1.4.0 the wp_wwrs_supplier_item table is truncated automatically. This wipes stale phpThumb / broken image URLs that were stored by 1.2.4-1.2.9 before the extractor was fixed. Next time any supplier item's modal is opened, it fetches fresh data.

1.2.13

  • Critical fix: the modal's Refresh button was silently a no-op. The JS was sending force=1 to the AJAX endpoint, but the PHP handler ignored the parameter and always returned the cached DB row. Since the 24 h TTL means we never re-fetch on view, this meant every subsequent image/price improvement was invisible on already-viewed items until either the row expired or was manually deleted.
  • Now the AJAX endpoint honours force=1 — clicking Refresh actually refetches the supplier page and updates the persisted row. This is what unblocks the image + price improvements from 1.2.5-1.2.12 for items that were viewed under older versions.

1.2.12

  • Image extractor now targets tubs.parts' actual product gallery classes: images inside .main_image (primary) and .sub_image (extra) are picked up directly. Runs before the click-to-enlarge / id-in-URL fallbacks so we never guess when there's a solid signal.
  • Works whether the class is on the <img> itself or on a wrapping <div> / <a> / <figure>.

1.2.11

  • Image extractor no longer requires the supplier item id to be in the image filename. Tubs.parts and similar osCommerce shops routinely name product images descriptively (Dessin sans titre (18).jpg, BoutonThermostat H30-H20.jpg, ...). New strategy:
    1. Any <img> or <a href> whose alt/title/anchor text contains “Click to enlarge”, “enlarge”, “click to zoom”, “view larger”, “full size” wins.
    2. Then the previous id-in-URL fallback (still useful when ids ARE present).
    3. Icons / logos / spacers are filtered out (based on filename + explicit small width/height).

1.2.10

  • Image extractor now unwraps phpThumb / TimThumb URLs: phpThumb.php?src=images/4224.png&w=100 becomes images/4224.png. That means every product on tubs.parts gets a real image (either the direct <a href> if present, or the underlying source of the phpThumb thumbnail).
  • Fewer situations where we silently return no image — previously we rejected all phpThumb candidates and if none other existed the modal was blank.

1.2.9

  • Image extractor now scores candidates and rejects known-bad thumbnail generators (phpThumb, TimThumb, cache/, resize= query args, _thumb / thumb_ in filename). Fixes the tubs.parts modal previously showing the phpThumb debug "error messages disabled" image.
  • Direct <a href> links to full-size images are preferred over <img src> when both are present.
  • Clean URLs (no query string) beat URLs with parameters.

1.2.8

  • Fixed price scanner: \b word boundary after non-ASCII currency symbols like € never matched, causing tubs.parts style prices 6,30€ to be silently dropped. Replaced with a Unicode-safe (?![\w]) lookahead.
  • Price scanner tuned for osCommerce / xtCommerce output (which is what tubs.parts runs).

1.2.7

  • Preview extractor gained supplier-id-aware fallbacks so it works with old-school osCommerce / xtCommerce shops (e.g. tubs.parts) that don't ship JSON-LD or OpenGraph:
    • Image: falls back to any <a> / <img> whose URL contains /images/{supplier_item_id}*.{png,jpg,jpeg,gif,webp}.
    • Price: falls back to scanning body text for currency patterns (6,30€, 1.999,50 DKK, $4.99, £4.50, 4,99 kr, ...). First match wins; currency is derived from the matched symbol / code.

1.2.6

  • New per-source option Ignore separators when matching SKUs. When enabled, dashes, underscores and spaces are stripped from BOTH the Woo SKU (after prefix removal) and the supplier model before comparing — e.g. Woo 581-01211090-25 now matches tubs model 0121109025 out of the box.
  • Wildcard tokens still work in combination: PF-XX-1N22 normalizes to PFXX1N22, wildcard is expanded, and matches Woo 582-PF-30-1N22 -> PF301N22.
  • Source form now supports checkbox config field type.

1.2.5

  • Supplier preview now extracts price, currency and a much better image. Extraction pipeline: JSON-LD (schema.org Product) first, then OpenGraph / Twitter meta, then microdata itemprop="image" / itemprop="price". Relative image URLs are resolved to absolute.
  • Preview card gained a highlighted price line with currency badge.
  • wp_wwrs_supplier_item table gained price and currency columns (schema upgraded automatically, DB version 1.3.0).

1.2.4

  • Supplier preview modal no longer relies on iframes (blocked by X-Frame-Options on tubs.parts and many others). Instead the plugin now fetches the supplier page server-side, extracts image, title, description and h1, and renders them as an inline preview card. "Open at supplier ↗" button remains for the full page.
  • Preview data is cached in a transient for 24 h per supplier item.
  • New AJAX endpoint wwrs_supplier_preview (nonce + manage_woocommerce protected).

1.2.3

  • Fixed URL template being mangled on save: {id} placeholder was stripped by esc_url_raw(). product_url_template is now a text field that preserves placeholders.
  • SKU prefix stripping now supports multiple regex patterns, one per line — e.g. put ^581-, ^582-, ^511- on separate lines if you don't want the default ^\d{3}- to match every three-digit prefix. First matching pattern wins.
  • Source form now supports textarea config fields.

1.2.2

  • Supplier item #NNNN is now ALWAYS clickable when we know how to build a URL. Auto-detects tubs.parts sources from the feed URL host and uses the built-in https://www.tubs.parts/en/-p-{id}.html pattern — no more required manual URL template config.
  • Same auto-detection for www.spafix.dk mirror hosts.
  • product_url_template config field still overrides the built-in patterns when set.

1.2.1

  • Fixed plugin row "Settings" link pointing at the old page=wwrs-sources slug — now correctly opens page=wwrs.
  • Supplier items on the Mapping tab are now clickable and open the supplier product page in an in-admin modal (iframe) so merchants can preview WHAT a supplier item like #2161 actually is without leaving WooCommerce. Falls back to opening in a new tab when the supplier blocks framing.

1.2.0

  • Unified admin surface: one Remote stock menu item under WooCommerce with WP-standard tabs (Sources, Mapping, Log).
  • Mapping: manual link field became a search-as-you-type input matching Woo SKU or title, showing up to 10 candidates. No more copy-pasting numeric IDs.
  • Mapping: every supplier row now shows a View at supplier ↗ link built from a per-source URL template (product_url_template, default https://www.tubs.parts/en/-p-{id}.html).
  • Mapping: candidate view fetches the supplier page's <title> on demand (24 h cached) so items like #449 show what they actually are.
  • Refreshed admin CSS — cards, spacing, status badges, matches the look-and-feel of WWSMP / WWSS.
  • New AJAX search endpoint wwrs_search_products (nonce + manage_woocommerce protected).

1.1.0

  • Explicit mapping between supplier items and Woo products/variations, stored in a new wp_wwrs_mapping table (N:N: one Woo product can be linked to items from multiple sources).
  • New admin sub-page WooCommerce → Remote stock mapping with filters (source / status / free text search), pagination and per-row actions (Find candidates, Ignore, Unlink).
  • Auto-suggest engine: per-source SKU transform (prefix regex + wildcard token) that turns supplier models like PF-XX-1N22 into Woo SKU candidate patterns like ^\d{3}-PF-[A-Z0-9]{2}-1N22$.
  • XML source config gained three new fields: SKU strip prefix, wildcard token and wildcard regex (defaults suit NNN- prefix + XX wildcard).
  • wwrs_get_remote_stock now consults the mapping table first and falls back to the previous SKU==model behaviour when no explicit mapping exists.
  • New linked / ignored / import_candidate statuses so unwanted supplier items disappear from the mapping list without being deleted.

1.0.2

  • XML source: auto-recover from feeds that declare encoding="UTF-8" but actually contain Windows-1252 / Latin-1 bytes (e.g. raw é as 0xE9). Body is transcoded to UTF-8 and the XML declaration is rewritten before parsing.

1.0.1

  • XML source: much better parse-error diagnostics (libxml errors, root element name, first bytes of response body, content-type).
  • XML source: strip UTF-8 BOM and leading whitespace before parsing.
  • XML source: detect HTML responses (e.g. supplier login page) and surface a clear error instead of a generic parse failure.
  • XML source: <item> elements are now located via //item XPath, so they are found regardless of wrapper element depth.

1.0.0

  • Initial release.
  • XML basic-auth source adapter.
  • Manual "Import now" from the admin sources screen.
  • wp_wwrs_stock table with atomic per-source replacement.
  • wwrs_get_remote_stock read filter.
  • Product metabox + variation field for mapping.
© 2026 Webalive - live website