=== Informedio Catalog Sync for WooCommerce ===
Contributors: wilcoxllc22
Tags: woocommerce, product import, wholesale, dropshipping, inventory sync, automated sync, supplier
Requires at least: 6.0
Tested up to: 7.0
Requires PHP: 7.4
Stable tag: 2.13.0
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Sync wholesale supplier catalogs into WooCommerce automatically. Works with S&S Activewear (free) and SanMar (Pro). Products, inventory, prices, and images — no CSV uploads.

== Description ==

Catalog Sync connects your WooCommerce store to wholesale vendor catalogs and keeps your products up to date — automatically.

Point it at a vendor, download their catalog, pick what you want to sell, map the fields to WooCommerce, and hit sync. Products appear in your store as fully built variable products with images, sizes, colors, brands, and pricing. No CSV imports, no copy-paste, no manual data entry.

**How it works:**

1. **Connect** — install a vendor, add your credentials, and test the connection from the Vendors page
2. **Download** — pull the latest catalog data from the vendor
3. **Import** — stage the raw data into organized tables
4. **Filter** — choose which brands, categories, or products to include
5. **Map** — assign vendor fields to WooCommerce product fields
6. **Update** — sync everything into WooCommerce as live products

Each step runs independently from a single admin console. You control what gets imported, how fields are mapped, and when products sync.

**Built for real catalogs:**

* Works with large supplier catalogs — 100,000+ products, no timeouts or memory errors
* Creates WooCommerce variable products with color and size as selectable attributes
* Downloads and attaches product images, color-specific variation photos, and brand logos
* Preserves your manual edits — sync never overwrites categories you've assigned by hand
* Re-sync anytime — updates existing products instead of creating duplicates

**Who is this for?**

Built for shops selling wholesale apparel and promotional products. Uniform stores, team-wear shops, promotional product distributors, and print-on-demand businesses working with wholesale suppliers like S&S Activewear and SanMar. If you spend hours a month copy-pasting product data from supplier spreadsheets into WooCommerce, this plugin replaces that entire workflow.

**Free vs Pro:**

The free plugin includes the full sync engine with S&S Activewear — connect, download, filter, map, and sync products with no restrictions and no license required.

[Catalog Sync Pro](https://informedio.com) unlocks additional vendors (SanMar and more), automated background syncing on independent catalog and inventory schedules via Action Scheduler, and priority support. Pro licenses start at $99/year with a 15-day free trial.

== Installation ==

1. Upload the plugin folder to `/wp-content/plugins/`
2. Activate the plugin through the WordPress Plugins menu
3. Navigate to **Catalog Sync → Vendors** to install and configure your vendor connections
4. Enter your vendor credentials, test the connection, and save
5. Navigate to **Catalog Sync → Add Products** and walk through the tabs: Download → Import → Filter → Map → Update
6. Pro users: visit **Catalog Sync → Schedule** to set up automated catalog and inventory sync intervals per vendor

== Frequently Asked Questions ==

= Does this replace WooCommerce CSV imports? =

Yes. Instead of exporting supplier data to CSV and importing it into WooCommerce, this plugin connects directly to the supplier and pulls products in automatically. No spreadsheets, no manual uploads.

= Does the plugin support large vendor catalogs? =

Yes. The system uses stream-to-disk downloads, batch processing, and staged imports to handle catalogs with 100K+ SKUs.

= Does it support multiple vendors? =

Yes. The free plugin includes S&S Activewear. Pro adds SanMar, with more suppliers on the roadmap.

= Can sync run automatically? =

Yes, on Pro. Each vendor gets two independent schedules — catalog (styles, images, descriptions, pricing) and inventory (stock only) — since inventory data changes far more often than catalog data. A scheduled catalog sync runs the complete pipeline: download, import, filter, map, and update. Inventory sync is lightweight — it queries the vendor API for current stock quantities and updates existing WooCommerce variations directly, without re-downloading or rebuilding the catalog. Both run automatically via Action Scheduler. You can also trigger an inventory sync manually from the Schedule page at any time. Manual sync from the Update tab always works regardless of license or schedule configuration.

= Does the plugin support WooCommerce variations? =

Yes. Products are grouped into variable products with color and size as variation attributes. Each SKU maps to one variation with the correct image.

= Will sync overwrite my manual product edits? =

Categories you assign manually are preserved on existing products. Sync only assigns categories when a product has none. Product names, descriptions, and prices follow the mapping profile.

= Does it support brand logos? =

Yes. Brand logos from the vendor catalog are attached to WooCommerce brand taxonomy terms automatically during sync.

= What vendor formats are supported? =

The plugin supports REST API (JSON) and SFTP/CSV vendor connections through its module system. Each vendor module declares its own transport, endpoints, and data format.

= Is S&S Activewear really free? =

Yes. S&S Activewear works fully with no license, no time limit, and no feature restrictions. Download, filter, map, sync, images, variations — everything works.

= What does Pro add? =

Pro unlocks additional vendors (SanMar is the first, with more planned), automated background syncing via Action Scheduler, and priority support. Free trial included.

= How does licensing work? =

Purchase a Pro license at informedio.com. Enter your license key on the Catalog Sync Dashboard in your WordPress admin. The plugin validates it against our server and unlocks premium features. Licenses are cached locally and re-checked weekly.

== Screenshots ==

1. Import dashboard — the whole workflow in one place
2. Filter builder — pick which brands and products to include
3. Field mapper — line up supplier data with WooCommerce fields
4. Sync progress — watch products come in as they process

== Changelog ==

= 2.13.0 =

Inventory sync, log maturity, and vendor neutrality

Inventory sync

* New: S&S Activewear inventory executor — updates WooCommerce variation stock quantities via the REST API inventory endpoint, batching styles in a single request per sync
* New: SanMar inventory executor now records runs in sync_runs — inventory freshness, vendor health, and sync success rate on the dashboard are now accurate
* New: Manual "Run now" button on the Schedule page — trigger an inventory sync for any vendor without waiting for the next scheduled run
* New: 2-hour and 4-hour inventory sync intervals added to the scheduler
* Changed: SanMar WSDL URL moved from a hardcoded PHP literal into manifest.json — the executor reads it from the database like every other endpoint
* Changed: SanMar endpoint seeder now loops all manifest endpoints instead of reading only the first one

Logging

* New: Log deduplication — consecutive identical messages for the same vendor increment a repeat count instead of inserting duplicate rows, keeping the log readable during persistent conditions
* New: Auto-escalation — a condition repeating 24+ times promotes from INFO to WARNING; 72+ times promotes to ERROR
* New: Repeat count badge (×N) displayed on log entries in the Tools > Logs tab
* Changed: Vendor display names shown throughout the UI — logs, dashboard, and filter dropdowns show "S&S Activewear" and "SanMar" instead of raw vendor keys
* Changed: Staging import log entries (CS-ST-001, CS-ST-002) now write in production instead of requiring debug mode

Reliability

* New: Orphaned sync run cleanup — runs stuck in "running" status for 2+ hours are automatically marked "abandoned" during daily maintenance
* New: sync_runs retention pruning — old run history rows are deleted on the same daily schedule as log pruning
* Changed: sync_runs recorder (start_sync_run / finish_sync_run) is now public and sync_type-aware, used by both catalog and inventory pipelines through a single canonical writer
* Changed: Inventory sync status derived from actual outcome (complete / partial / failed) instead of being hardcoded to "complete"

Vendor neutrality

* Fixed: Core staging executor no longer calls S&S-specific functions by name — vendor-neutral utilities replace all six hardcoded call sites
* Fixed: 12 default-to-'ss' fallbacks removed from AJAX handlers, helpers, and UI — missing vendor key now returns an error or empty result instead of silently operating on S&S data
* Fixed: is_free_vendor() consolidated to a single implementation in the license class — two diverged copies removed
* Fixed: Vendor identity lookup in both setup files now matches on vendor_key only (prepared statement) instead of also matching on the user-editable vendor_name column
* Fixed: file_type column name corrected in S&S endpoint seeder — was writing to nonexistent file_format column, silently dropping the value
* Fixed: Dashboard vendor display name resolver reads from the vendors table with static caching instead of a hardcoded array
* Fixed: Dashboard vendor health avatar color uses clean vendor_key comparison instead of substring matching against the display label

= 2.12.0 =

Extension points for add-ons

* New: `catalogsync_after_catalog_build` action — fires after a successful catalog rebuild, allowing add-ons to post-process catalog rows (e.g., AI enrichment, translation, category mapping) before the executor pushes them to WooCommerce
* New: `catalogsync_dashboard_after_mid_row` action — fires between the mid row (chart + vendor health) and the bottom row (activity log + scheduled actions) on the dashboard, allowing add-ons to inject their own cards using the existing .cs-dash-card visual language
* Documentation: both hooks are documented via inline doc-blocks describing the contract, parameters, and stability guarantees for future add-on developers

= 2.11.0 =

Keyword indexing, guided imports, and clearer mapping

* New: Keyword index — comma-delimited columns (e.g. KEYWORDS) are parsed into individual terms after each import, so the Field Explorer shows real keywords like "scrub" or "medical" with accurate row counts instead of the raw cell
* New: Click-to-use in the Field Explorer now creates a filter rule automatically when none exists for that field, instead of only adding to an existing rule
* New: Replace-existing-data option on each Import card — clears that vendor's staging data before importing so re-downloading the same brand doesn't stack duplicate rows. Per-card, so importing a second brand with the option unchecked keeps the first brand's rows.
* New: Plain-language image field descriptions on the Map tab — each gallery image column now shows what it is (e.g. "Worn by model, front — changes per color" vs "Main style photo — same for all colors")
* New: Resizable preview panel on the Map tab — drag the divider to widen or shrink the live preview
* Fixed: Variation color images now attach correctly — the "Variation Color Image" role was restored to the Map tab and its save/compile path, so per-color images map to each variation again (regression from v2.6.0)
* Fixed: Field Explorer values with surrounding quotes are now stripped before building the filter clause, so exact-match filters work as expected
* Fixed: Map tab JavaScript now cache-busts on version change, so UI updates load without a manual hard refresh

= 2.10.0 =

Field Explorer & file structure overhaul

* New: Field Explorer panel on the Filter tab — select any field to see all distinct values with row counts, sorted by frequency or alphabetically
* New: Click-to-use — click any value in the Field Explorer to insert it into the active filter rule
* New: Search within field values for fast lookup in high-cardinality columns (e.g., COLOR_NAME, KEYWORDS)
* New: Browse Fields chip bar — explore any staging column without adding a rule first
* New: Resizable filter/explorer panels — drag handle between the rule builder and Field Explorer to adjust column widths
* New: Field explore AJAX endpoint (catalogsync_filter_field_explore) returning grouped distinct values with counts
* Fixed: Saving SOAP credentials no longer wipes SFTP password and vice versa — blank password fields on update are now treated as "unchanged"
* Changed: Plugin file structure reorganized — classes to includes/classes/, tab templates to includes/tabs/, standalone AJAX handlers consolidated into includes/ajax/
* Changed: Filter JS version string now uses CATALOGSYNC_VERSION constant for automatic cache-busting on every release

= 2.9.0 =

Enhanced logging

* New: Structured error code system (CS-XX-NNN) across all log entries — every message carries a unique, greppable code for fast diagnosis
* New: Human-readable log messages — store admins can understand what happened without reading source code
* New: ERROR-CODES.md internal reference mapping all 72 error codes to their component, severity, and message
* Changed: Removed table names, filesystem paths, function names, hook names, and DB error strings from all log output and AJAX error responses
* Changed: Diagnostic context (vendor, endpoint, HTTP code, byte counts, row counts) preserved in structured JSON context column
* Changed: catalogsync_log_sync_summary rewritten with CS-UP-001 through CS-UP-101 codes and human-readable labels
* Changed: SFTP transport fail/log methods no longer expose host:port in context — uses component tagging instead
* Changed: Download handler AJAX error responses no longer include internal table names or temp file paths
* Changed: flush_error_log source tags use generic component names instead of filenames
* Files touched: 20 files across ajax handlers, executors, transport, scheduler, tools, vendor setup, and debug-helpers

= 2.8.0 =

Dashboard

* New: KPI-driven operational dashboard replacing the pipeline wizard layout
* Five live KPI tiles: catalog coverage, inventory freshness, sync success rate, avg sync duration, in-stock rate — each with trend badges and graceful degradation when sync history is not yet available
* Vendor health cards with per-vendor metrics (catalog rows, last catalog sync, last inventory sync) and color-coded status bars
* Sync volume chart showing products created vs updated per day over 14 days
* Activity log displaying last 7 sync runs with status, row counts, and relative timestamps
* Scheduled actions panel with countdown timers, pulled live from Action Scheduler
* Contextual alert bar surfaces stale inventory or missing sync data automatically
* Dashboard data layer split into dedicated includes/dashboard-kpis.php — all SQL queries isolated from the template for maintainability
* Dashboard styles split into dedicated assets/catalogsync-dashboard.css scoped to .cs-dash
* All KPI functions are schema-defensive: check table and column existence via information_schema before querying, return nulls when data is unavailable

= 2.7.0 =

Tools page

* New: Logs tab — DB-backed log viewer with card-row layout, level/vendor/component filtering, sort (newest/oldest/errors first), relative timestamps, click-to-expand context JSON, per-row and bulk copy/email actions
* New: Per-component schema version tracking on the Database tab — installed vs current version comparison with status badges, auto-migration triggered by schema file changes independent of the plugin version
* Settings tab Save button now functional — persists logging and performance configuration via AJAX

Logging and diagnostics

* Download handler fully instrumented — all success and failure paths now log with vendor context, curl exit codes, URLs, and stderr
* Timestamps stored in WordPress local timezone instead of UTC
* Log retention pruning uses WordPress local time

Vendor credentials

* Credential resolution simplified to canonical column reads (user_name, api_key) — removed fragile six-deep fallback chain that could silently fail on empty-string columns
* Vendor Setup save button disabled by default until test connection succeeds, preventing accidental credential wipes

S&S Activewear

* Fixed: inventory endpoint missing remote_url in manifest.json, causing download failures

= 2.5.0 =

Vendor management

* New: Vendors submenu — vendor management is now a standalone admin page with card-based layout, separate from the Add Products pipeline
* Each vendor gets a detail page with stats, credential forms, and connection log — replacing the old inline config card
* Vendors tab removed from Add Products; default tab is now Download
* "Manage vendors" button in the Add Products top bar links to the new Vendors submenu

= 2.4.0 =

Inventory sync

* New: SanMar inventory executor — updates WooCommerce variation stock quantities via the PromoStandards Inventory V2.0.0 SOAP API, querying only styles already in your store
* Scheduled inventory sync jobs now dispatch to vendor-specific executors via a keyed action hook, keeping the shared scheduler vendor-neutral
* Products created by catalog sync now carry _catalogsync_vendor_key postmeta so the inventory executor can identify which products belong to which vendor

Vendor credentials

* Added SOAP API credential fields (Customer Number, Web Services Username, Web Services Password) to the Vendor Setup form for FTP-type vendors
* Three new columns on the vendors table: soap_customer_number, soap_username, soap_password
* SOAP credentials are separate from SFTP credentials per SanMar's integration guide

Admin UI

* Download and Import tabs now use a compact two-column tile grid instead of full-width stacked cards
* Removed progress bars and log boxes from Download and Import tiles — status feedback is now an inline text label per tile

= 2.3.0 =

Scheduling

* New Schedule submenu — automated catalog and inventory sync on independent per-vendor intervals, gated to Pro Developer and Agency tiers
* Scheduled catalog sync now runs the complete pipeline (download, import, filter, map, update) instead of only the final sync step, so automated runs pull fresh vendor data rather than re-syncing stale staging data
* Download logic for FTP and API vendors extracted into reusable functions shared by both manual and scheduled sync
* Inventory-only scheduling can be configured and will fire on schedule, but its lightweight executor has not shipped yet in this release

Admin UI

* Renamed "Import Console" submenu to "Add Products"

For the full changelog, see [changelog.txt](changelog.txt).

== Upgrade Notice ==

= 2.13.0 =

After deploying: go to Catalog Sync → Tools → Database and click Update All to add the new repeat_count and last_seen_at columns to the logs table, and to seed the SanMar inventory endpoint. Inventory sync is now live for both S&S Activewear and SanMar — visit Schedule to set your preferred interval or click Run Now to test immediately.

= 2.4.0 =

After deploying: go to Catalog Sync → Add Products → Tools and click Run All to add the new SOAP credential columns to the vendors table. Enter your SanMar.com credentials on the Vendors tab under "Web Services API." Re-run the Update step on any existing SanMar products so they get tagged with the vendor key meta the inventory executor needs. Port 8080 outbound may need to be whitelisted on shared hosting for the SOAP API calls.

= 2.3.0 =

After deploying: go to Catalog Sync → Add Products → Tools and click Run All to add the new catalog_sync_interval and inventory_sync_interval columns to the vendors table. No data loss — dbDelta only adds columns. Automated scheduling requires an active Pro Developer or Agency license; manual sync is unaffected either way. Note the "Import Console" submenu is now labeled "Add Products" — same page, same URL, label only.

= 2.2.0 =

After deploying: go to Catalog Sync → Tools and click Run All to add new join columns to vendor_endpoints and re-seed endpoint configurations. No data loss — dbDelta only adds columns. Existing S&S filter profiles, mappings, and products are unaffected.

== License ==

This plugin is licensed under the GPLv2 or later.

== Credits ==

Developed by Informedio.