== Changelog ==

= 2.2.0 =

Framework

* Catalog builder rewritten — reads join declarations from vendor_endpoints instead of hardcoded table joins; supports both multi-table and single-table vendor layouts through the same code path
* vendor_endpoints schema extended with join_to, join_on, and join_type columns; join relationships are declared in vendor manifests and seeded at install time
* Filter and mapping example values now work for any staging layout — single-table vendors no longer require a styles table to populate field hints
* Import tab supports per-file cards for FTP-transport vendors alongside existing API endpoint cards
* Vendor installer functions resolved via discovery — no hardcoded vendor function names in shared code

Product sync (executor)

* Executor reads normalized catalog columns directly — removed hardcoded S&S staging-name translation table; all vendors now sync through the same deterministic code path
* Variable product grouping uses a canonical style-key resolver that reads whichever style identifier column is present in the catalog (styleID for S&S, style_no for SanMar), so single-table flat vendors build variable products with color/size variants on the same path as multi-table vendors
* Self-healing variation upsert — when a SKU is held by a wrong-shape product (e.g. a stale simple product from an earlier run), the stale post is deleted to free the SKU and the variation is rebuilt correctly; a re-run repairs products whose shape changed instead of failing on duplicate-SKU collisions

Images

* Image Manager recognizes absolute_url source mode (used by SanMar) as equivalent to full_url — previously, absolute URLs silently returned empty and images never attached
* Color Image and Brand Image added as mapping targets — per-color variation images and brand logos now populate from the mapping profile for all vendors
* Mapping compiler carries _color_image_url and _brand_image targets through to the catalog builder so the image columns are filled during catalog assembly

Mapping

* Added color_image_url (Color Image) and brand_image (Brand Image) to the Map tab target list
* Updated mapping notes: image_url, color_image_url, and brand_image reflect their active role in the Image Manager rather than future-ready placeholders

Tools

* Database Migration rebuilt as discovery-driven per-vendor Repair system — each discovered vendor gets its own Repair button with inline status feedback; Run All processes core tables and all vendors sequentially
* Vendor selector auto-submits on change — Set Vendor button click no longer required

UI

* Fixed elapsed timer regression — startElapsed() now clears any existing interval before creating a new one, preventing orphaned timers that kept incrementing after job completion

Licensing

* Added EDD Software Licensing integration — activate, deactivate, and validate licenses from the Dashboard card
* S&S Activewear is the free-core vendor and works without a license or restrictions
* Additional vendors (SanMar first) require a valid Pro license; selecting a premium vendor without a license redirects to the Dashboard with an upgrade prompt
* All vendor-scoped AJAX operations are gated — premium vendor sync requests return an error without a valid license; S&S operations pass through freely
* License status cached in a 7-day transient; weekly WP-Cron re-check confirms subscription health without hitting the server on every page load
* Action Scheduler automated syncing gated to Pro Developer (Price ID 2) and Agency (Price ID 3) tiers
* Dashboard license card shows activation status, tier label, masked key, and expiration date; unlicensed users see an "Upgrade to Pro" upsell with link to informedio.com

= 2.1.4 =

Maintenance

* Removed a stray debug log write (file_put_contents to fatal.log) that bypassed the plugin's protected logging mechanism

= 2.1.3 =

Review compliance and hardening

* Updated bundled DataTables from 1.13.11 to 2.3.8 (latest stable)
* Ajax endpoint is no longer hardcoded — now passed to JS via wp_localize_script() using admin_url()
* SQL identifier handling tightened: preview field validated against the table's actual columns; vendor key validated against the vendors registry before building any table name
* Removed dead Open Preview button and its orphaned server-side handler (depended on a missing file)
* Removed placeholder Schedule tab from the Import Console

= 2.1.2 =

Compliance and hardening

* Renamed plugin to "Informedio Catalog Sync for WooCommerce" for a distinct, brand-led name
* Runtime data (cached vendor payloads, logs) is now stored under the uploads directory instead of the plugin folder
* Added recursive input sanitization to the mapping and update-product AJAX handlers
* Updated bundled DataTables to 1.13.11
* Moved the admin menu to a lower position to respect the core WordPress menu hierarchy

= 2.1.1 =

Product structure

* Products now group by styleID only — all color variants of a style are consolidated into one variable product instead of creating a separate product per color
* Color (pa_color) is now a variation attribute alongside size (pa_size), enabling color + size selectors on the single product page
* Each variation carries both attribute_pa_color and attribute_pa_size postmeta after save

Image pipeline

* New: variation color images — colorFrontImage attached to each product variation via WC_Product_Variation::set_image_id() so the correct photo appears on color selection
* New: brand logo images — brandImage attached to WooCommerce product_brand taxonomy terms via thumbnail_id so logos appear on brand archive pages and sidebar filters
* Variation image cache scoped per style group — same color URL sideloaded once regardless of how many sizes share it
* Brand image cache static across all style groups in the request — each brand logo downloaded once per sync run
* Image failures wrapped in try/catch and logged as warnings; product saves never interrupted by image errors

Brand assignment

* Added wp_set_object_terms() fallback for brand assignment when WooCommerce Brands feature toggle is off or set_brand_ids() is unavailable
* Pending brand stored in product meta and flushed immediately after parent save to handle new products where post_id is not yet known at assignment time

Manual edit protection

* Categories on existing products are only updated when the product currently has no categories assigned, preserving any manually set categories
* New products always receive categories from the feed

Schema

* Added brandImage varchar(255) to staging_styles table
* Added brand_image varchar(255) to staging_catalog table
* catalog-builder SELECT now includes COALESCE(s.brandImage, '') AS brand_image

Tools

* New: Run Database Migration button in Catalog Sync → Tools — fires dbDelta() against all Catalog Sync tables to safely add new columns without touching existing data

= 2.1.0 =

Filter builder

* Per-rule AND/OR logic: each rule chooses how it joins to the rule above it, replacing the single global connective
* Nested groups: rules can be collected into groups with their own logic, enabling compound conditions such as BrandA OR BrandB OR (BrandC AND title contains "scrub")
* Compiler rewritten as a recursive tree walk; every group emits its own parenthesized clause to preserve explicit precedence
* Empty groups are skipped during compilation rather than emitted as (1=1), preventing accidental match-everything branches when an OR-joined group has no children
* Backward compatible: filter profiles saved under the previous flat shape continue to load, render, and compile unchanged
* Saved-filters list now counts rules across the full tree, not just the top level

Synchronization performance and logging

* Deferred WC_Product_Variable::sync() to the end of each batch instead of firing per variation group, eliminating a severe per-row performance regression on large brands
* Added a static guard around catalogsync_ensure_wc_attribute() to memoize taxonomy-existence checks within a batch
* Per-batch progress is now logged with rows-per-second telemetry and surfaced in the update UI progress bar (real percentage rather than a hardcoded mid-run value)
* Unified background-processor and executor logging through a single structured logger with consistent log levels and correlation context

Schema

* total_rows is now captured on the import job row and exposed in the background status response so the UI can compute true progress

= 2.0.0 =

* Major architecture redesign to endpoint-based ingestion
* Removed monolithic catalog ingestion model
* Introduced multi-endpoint staging
* Added inventory warehouse normalization
* Implemented assembled catalog working dataset
* Reworked ETL pipeline
* Introduced stream-to-disk downloads
* Complete UI and workflow overhaul of the ETL console
* Improved scalability for large vendor catalogs
* Refactored execution to use vendor_key for deterministic file resolution
* Standardized execution via single entry point with endpoint routing
* Introduced specialized handling for nested inventory data
* Improved reliability for large inventory imports
* Enhanced execution consistency for nested vendor payloads
* Resolved issues where inventory imports could complete without inserting data
* Eliminated duplicate execution conflicts
* Enforced strict separation of execution responsibilities

= 1.0.1 =

* Fixed JS loading issue causing handleVendorSelection undefined error
* Removed API URL dependency from vendor configuration
* Replaced API URL with Vendor Key
* Hid SFTP host and storage path from UI
* Improved vendor selection logic to be fully database-driven
* Removed hard-coded vendor assumptions
* Introduced deterministic vendor installation architecture
* Added vendor manifest and installer pattern
* Implemented vendor discovery system
* Fixed installer path resolution issues
* Stabilized connection test and save flow
* Fixed download corruption issues
* Resolved JSON parsing errors

= 1.0.0 =

* Initial public release