Skwirrel PIM sync for WooCommerce connects your WooCommerce webshop to the Skwirrel PIM system. Products, variations, categories, brands, manufacturers, images, and documents are synchronised automatically or on demand.
Features:
- Full and delta (incremental) product synchronisation
- Simple and variable product support with ETIM classification for variation axes
- Automatic category tree sync with parent-child hierarchy
- Brand sync via WooCommerce native product_brand taxonomy
- Manufacturer sync with dedicated product_manufacturer taxonomy
- Product image and document import into the WordPress media library
- Custom class attributes (alphanumeric, logical, numeric, range, date, multi)
- Configurable product URL slugs (source field, suffix, update on re-sync)
- GTIN and manufacturer product code search filter on the product list page
- Scheduled synchronisation via WP-Cron or Action Scheduler
- Manual synchronisation from the admin dashboard with live progress tracking
- Date-grouped sync history (last 20 runs)
- Stale product and category purge after full sync
- Delete protection with warnings and automatic full re-sync
- Multilingual support with 7 locales (nl_NL, nl_BE, de_DE, fr_FR, fr_BE, en_US, en_GB)
Requirements:
- WordPress 6.0 or higher
- WooCommerce 8.0 or higher (9.6+ recommended for native brand support; tested up to 10.6)
- PHP 8.3 or higher
- An active Skwirrel account with API access
3.8.2
Release-hygiene fixes for
WordPress.org Plugin Check:
- Stop shipping dev-only files in the SVN trunk. The 10up deploy action skips
.distignore whenever a BUILD_DIR is configured, so the previous releases inadvertently shipped empty composer.json, phpstan.neon.dist, phpunit.xml.dist, phpunit-integration.xml.dist, .phpcs.xml.dist, .gitignore, and .distignore placeholder files. Those placeholders have been removed from the plugin source so the deploy ZIP only contains runtime files.
- Suppress Plugin Check false positives in plugin code: the
active_plugins activation check is the WordPress core filter (not a plugin-defined hook), the _skwirrel_category_id term-meta lookup queries are documented as having no WP API equivalent, and the 'meta_key' array key inside a logger context is correctly flagged as not a database query argument. No runtime behavior changes.
3.8.1
- Fix: grouped-products sync now honours every configured
dynamic_selection_id. The 3.8.0 multi-selection fix only covered the main fetch loop; the grouped-products prefilter still used collection_ids[0] and silently skipped grouped products whose members lived only in selections 2..N. With this patch, a grouped product is kept whenever any of its members appears in any of the configured selections.
3.8.0
Media — real Skwirrel ↔ WordPress mapping + content-change detection:
- Every imported attachment now stores the Skwirrel
product_attachment_id as _skwirrel_attachment_id post meta. Re-syncs locate existing media by that stable id first; URL-hash matching is the legacy fallback. CDN URL rewrites no longer create duplicate WP attachments.
- The API's
file_sha256_checksum lands on the WP attachment as _skwirrel_file_checksum. A re-sync that sees a different checksum replaces the underlying file in place — same WP attachment id, fresh bytes, sub-sizes regenerated, mime type updated. Failed downloads leave the existing attachment untouched.
- Offload-plugin-safe missing-file guard — when the local file is gone the WP attachment record is preserved (no
wp_delete_attachment() is ever invoked, which would have triggered offload-plugin hooks that may purge remote storage). Only the Skwirrel-side meta is cleared so the next sync can download fresh. New skwirrel_wc_sync_attachment_is_valid filter lets offload-aware site code declare an attachment valid even when the local file is missing.
- Lazy migration: re-syncs of attachments imported before 3.8 silently backfill the new meta keys from the API payload. No re-download on upgrade.
Sync safety — fixes for issues surfaced in code review:
- Mutex on concurrent runs:
run_sync() refuses to start when another run's heartbeat is still fresh, preventing the queue, per-product synced_at meta and purge step from being raced. A stale heartbeat is taken as "previous run died" and the new run takes over.
- The global queue truncate at sync startup is gone. Each run uses its own
sync_run_id and only touches its own rows; defends queue contents even if the mutex is bypassed.
- Pagination atomicity: a later-page fetch failure is now a hard abort. Previously the run continued through every phase, advanced
last_sync, and ran stale-product purge — at worst trashing the products that lived on the un-fetched pages.
- Multi-selection support in the main fetch:
getProductsByFilter is now called once per configured selection id. The previous code silently used only the first id, dropping every product that lived only in selections 2..N.
- Empty cross-sells / upsells now actually clear. Previously an API payload that returned zero relations left existing WC cross-sells/upsells in place forever.
Plugin Check submission cleanup:
.distignore excludes all dev tooling configs from the deploy ZIP.
Tested up to: 6.9.4 → 6.9 (wp.org accepts only major.minor).
- Bulk SQL in the purge handler reworked so
Plugin Check's static analyser can verify int-sanitised IDs in the IN-clauses.
- Google Fonts enqueue now passes a version string instead of
null.
Tests:
- 237 unit + 45 integration tests (up from 169 + 11 in 3.6.x). New
MediaImporterIntegrationTest (10 cases) and SyncSafetyIntegrationTest (8 cases) pin every new behaviour.
3.7.0
- Bump minimum PHP version to 8.3 (PHP 8.1 reached end-of-life on 2025-12-31; 8.2 is in security-only support until 2026-12-31).
Requires PHP and composer.json runtime constraint both updated.
- Bump minimum Node.js version to 22 LTS for the local dev environment (
package.json engines.node). Node 18 reached end-of-life in April 2025 and Node 20 maintenance ends April 2026.
- CI: bump GitHub Actions PHP version from 8.1 to 8.3 to match the dev tooling lock file (Pest 3 / PHPUnit 11 require PHP 8.2+). Cache key updated accordingly.
.wp-env.json: bump phpVersion to 8.3 for parity with CI and the runtime floor.
- Internal: aligned source files with the WordPress coding standards now that CI no longer fails before phpcs runs. Class files renamed to
class-skwirrel-wc-sync-{slug}.php (full class name in kebab-case); the Skwirrel_WC_Sync_Plugin bootstrap class extracted from skwirrel-pim-sync.php into its own file. ~125 Yoda condition flips, ~33 $camelCase → $snake_case local variable renames, removed $mapper parameter from Skwirrel_WC_Sync_Category_Sync::assign_categories() (was unused), renamed $object → $wc_object in Skwirrel_WC_Sync_Variation_Attributes_Fix::fix_rest_response_attributes() (PHP 8.2+ reserved keyword). No functional changes.
3.6.1
- Fix: ship files that were missing from the 3.6.0 build —
class-pim-link.php (the "Open in Skwirrel" deep-link implementation), the updated class-admin-settings.php (Settings-saved notice + transient-based test result), the updated class-product-sync-meta-box.php (PIM link button), the assets/s.png button icon, and the corresponding .po/.mo translation updates. Without these files an install of 3.6.0 fatalled on activation with "Failed opening required ... class-pim-link.php"
3.6.0
- "Open in Skwirrel" deep-link — Skwirrel meta box on the product edit screen and each row on the WP Products list now offer a button that jumps straight to the matching product in the Skwirrel PIM web UI. The link uses the host from the JSON-RPC endpoint. Simple products use
/catalogue/products/edit/{product_id}; variable/grouped product shells use /catalogue/grouped-products/edit/{grouped_id}.
- "Settings saved" notice on the settings page — saving settings now shows a proper confirmation. The connection test result moved to a transient so it no longer re-displays after every save (previously a stale
?test=ok URL parameter caused the test-success notice to fire on save).
- New
skwirrel_wc_sync_after_attributes_fetched action hook — fires during the attributes phase right after a product's enriched payload (with _etim and _custom_classes) is fetched and before the WooCommerce attribute table is written. Enables site-specific code to persist the enriched payload as post meta for custom frontend rendering. Hook signature: do_action( 'skwirrel_wc_sync_after_attributes_fetched', int $wc_id, array $attr_product, ?array $group_info ). Fires in both the bulk Phase 3 loop and the single grouped product re-sync path
- Fix: variation filter values no longer empty during sync — pre-sync rebuild of the variable product shell wiped the parent's term-options to
[] for the entire duration of the sync, leaving the frontend variation filter (storage, color, connectivity, etc.) empty until the sync finished. The shell-rebuild now preserves existing term-options for each axis taxonomy
flush_parent_attribute_terms() is now authoritative — at the end of Phase 3 the parent's variation taxonomy term-list is rebuilt as exactly the set of term IDs whose slugs appear in the current children's attribute_pa_* post meta. Stale terms from removed variants are dropped (previously merged in indefinitely); new terms from added or updated variants are picked up. Replaces the previous merge-on-merge pattern with a single derived-from-children compute
3.4.0
- Live sync log viewer on the Debug page — tails the current sync log file with 2-second polling, auto-scroll, pause/clear/download controls
- "View live log" anchor link on the in-progress sync banner jumps straight to the live log
- Active log filename now tracked in a WP option so the viewer follows sync runs across page refreshes
- Dashboard Debug block relabelled to surface the live log alongside variation attribute troubleshooting
- CI actions bumped to Node 24 — checkout/cache/upload-artifact/github-script
3.3.0
- Log viewer performance — progressive rendering (200 lines/frame), chunked server loading (100 KB/request), and download button
- API Response meta box for grouped products — collapsible JSON display with syntax highlighting
- Lazy-loaded variation API responses via AJAX with individual collapsible sections
- Single grouped product sync — "Sync this product" button now works for variable/grouped products
- Grouped product ID stored as variation meta for direct group membership lookup
- Price fix: "Prices managed outside Skwirrel" now also protects simple product prices (previously only variations)
- Quick-scroll link from Skwirrel sidebar meta box to API response section
3.2.2
- New "Prices managed outside Skwirrel" setting — when enabled, the PIM sync no longer overwrites existing variation prices with 0 when the PIM payload contains no price. Use this when prices are synced from a separate system (e.g. ERP).
3.2.1
- Single-variant groups synced as simple products instead of variable products
- Custom features as variation axes alongside ETIM features
- Custom feature matching by ID with translated labels
- Attribute label auto-update for numeric and cc_ prefixed labels
- No duplicate attributes for custom feature variation axes
- Phase 3 custom class fetch when grouped products enabled
3.2.0
- Custom class collection ID — new required setting for product fetching
- Custom classes included in bulk product fetch
- Text features (type T) now stored as product attributes
- GTIN / Variant visibility toggles (default: hidden)
- Sync aborts with a clear error when custom class collection ID is not configured
3.0.0
- Virtual product content — variable products inherit name, descriptions, categories from virtual products
- Variation slugs — deterministic URL slugs generated from attribute values during sync
- Variation permalinks — optional clean URLs: /product/{product-slug}/{variation-slug}/
- Enhanced Skwirrel meta box — navigation links between parent and variation products
- Theme API — helper functions for theme developers (variation URLs, thumbnails, default variations)
- Example theme snippets in snippets/ directory
2.6.2
- Fix false "not managed by Skwirrel" message on variable products
2.6.1
- Fix related products API flag and add smart relation type mapping (auto/cross-sells/upsells/both)
2.6.0
- Related products sync — sync Skwirrel related products as WooCommerce cross-sells, upsells, or both
- New settings for related products mapping type
2.5.0
- Variant label setting — choose which field shows in the variant dropdown (SKU, ERP description, or product name)
- Custom class attribute visibility filter — control which custom class attributes are visible on the product page
2.4.4
- Fix "Stop sync" button — now checks during phases, not just between them
- Show failed sync timestamp and error in status card
2.4.3
- Flush WooCommerce object cache after every product in all processing phases
2.4.2
- Flush WordPress object cache between sync phases to reclaim memory
2.4.1
- Fix OOM in grouped products pre-sync phase — flush wpdb memory between API pages
2.4.0
- Deferred attribute fetch — ETIM and custom classes fetched per-product in attribute phase instead of bulk fetch
2.3.5
- Aggressive wpdb memory cleanup after every product in all sync phases
2.3.4
- Fix OOM during fetch — flush wpdb between batches, default batch size 10
2.3.3
- Fix OOM during fetch phase — smaller API batches + wpdb memory flush between pages
2.3.2
- Fix unexpected output during plugin activation
2.3.1
- Use WordPress timezone for log filenames instead of UTC
2.3.0
- Database-backed sync queue — product data stored in temporary DB table instead of memory, preventing OOM crashes on low-memory servers
- Products processed one at a time per phase via cursor pattern (O(1) memory usage)
2.2.9
- Convert existing simple products to variations when a grouped product sync encounters a duplicate SKU
- Reduce memory usage during phased sync by freeing heavy product data after each phase
2.2.8
- Simplify per-product category assignment — use resolved map from tree sync instead of recursive per-product resolution
2.2.7
- Add "Stop sync" button to progress banner — abort a running sync from the dashboard
- Log timestamps now respect the WordPress timezone setting
2.2.6
- Add include_contexts to category API call, improve category sync diagnostics
2.2.5
- Fix approved download directory: enable existing disabled directories during sync
2.2.4
- Fix category sync — use correct API parameter name for fetching categories
- Fix per-product category assignment when API returns ID-only category data
2.2.3
- Dark terminal-style log viewer with syntax highlighting for log levels
- JSON objects and sync separators styled for readability
2.2.2
- Raise PHP memory limit at sync start to prevent OOM crashes on large API responses
- Detect fatal errors (OOM) during sync and record them as failed results
- Fixes silent sync failures showing stale success status
2.2.1
- Separate "Sync Logs" settings section with per-trigger log mode (per sync or per day)
- Add "Manual (no auto-delete)" option to log retention
- Fix super category ID field width to match selection IDs field
2.2.0
- Per-sync log files — each sync run writes to its own log file for easy debugging
- Manual syncs get a unique log file; scheduled syncs share a daily log file (appended)
- Log viewer modal in sync history — click "View" to read log contents inline
- Configurable log retention (12h, 1d, 2d, 7d, 30d) — old files cleaned up automatically
2.1.5
- Recursively fetch full category tree from API — all depth levels are now synced, not just direct children of the super category
2.1.4
- Auto-register WP uploads directory as WooCommerce approved download directory during sync
- Fixes "downloadable file not in approved folder" errors for imported PDFs
2.1.3
- Store Skwirrel API response for all product types: variations and variable product shells now also save _skwirrel_api_response
2.1.2
- Fix grouped products ignoring dynamic selection ID — post-filter groups against selection product list
- Fetch allowed product IDs from selection before processing groups, skip groups with no matching members
2.1.1
- Fix grouped products ignoring selection ID filter — pass dynamic_selection_id to getGroupedProducts
- Store raw Skwirrel API response as _skwirrel_api_response post meta during sync
- Add dedicated "Skwirrel API Response" meta box on the product edit screen showing the stored JSON
2.1.0
- Selection ID is now required — sync aborts if no selection ID is configured
- Add "Show API response" button in the Skwirrel product meta box to view raw JSON from the API
- Reduce batch size maximum from 500 to 50, default from 100 to 10
- Fix translation: selection ID hint incorrectly said "category IDs" in all locales
2.0.8
- Add raw API response logging for getCategories and per-product _categories data (verbose mode)
2.0.7
- Fix category tree sync failing when API returns single root category object instead of array
- Categories from getCategories are now correctly extracted from root _children when super category ID is used
2.0.6
- Add diagnostic logging for category-to-product assignment to trace resolution failures
- Log each category resolve step (meta lookup, name fallback, creation) when verbose logging is enabled
- Warn when categories are extracted from API but no WooCommerce term IDs could be resolved
- Check and log wp_set_object_terms errors instead of silently ignoring failures
2.0.5
- Update README and plugin description to reflect current feature set
- Replace "ERP/PIM" references with "PIM" throughout
- Update WooCommerce minimum to 8.0 (9.6+ recommended for native brand support)
- Update WooCommerce tested up to 10.6
- Update WordPress tested up to 6.9.4
2.0.4
- Inline "Update on re-sync" toggle in Permalinks section — saves instantly via AJAX
- Slug warning only shown when "Update on re-sync" is enabled and settings have changed
- Persistent hint when re-sync is enabled warning about URL overwrite and SEO impact
- Add batch size hint text (1–500)
2.0.3
- Add Permalinks section in Settings showing current slug configuration with link to Permalinks page
- Show warning when slug settings change, advising a full resync and potential link breakage
- Add Selection IDs hint link to Skwirrel selections page (dynamic subdomain URL)
2.0.2
- Add GTIN / Manufacturer product code search filter on product list page
- Store product GTIN and manufacturer product code as dedicated meta during sync
- Add subtitles to Debug and Danger Zone dashboard blocks
2.0.1
- Rename "Collection IDs" to "Selection IDs"
- Add API token creation link with dynamic subdomain URL
- Add category finder link on Super category ID field
- Move WordPress admin notices below the Skwirrel header
2.0.0
- New admin dashboard with block-grid layout replacing the tab-based UI
- Sync progress banner with 6-phase checklist and live counters
- Date-grouped sync history table (Today, Yesterday, day name, or date)
- Settings page redesigned with grouped fieldsets and Tailwind-inspired styling
- Simplified API connection: subdomain-only input with visual prefix/suffix
- Remove auth type selector (always uses static token)
- Sync Logs block links directly to WooCommerce logs
- Debug and Danger Zone inline in the dashboard grid
- Full translation update for all 7 locales (nl_NL, nl_BE, de_DE, fr_FR, fr_BE, en_US, en_GB)
1.10.1
- Add Domain Path header for automatic translation loading on WordPress 6.7+
- Add load_plugin_textdomain() fallback for older WordPress versions
- Add nl.mo/nl.po locale files for sites using "nl" instead of "nl_NL"
- Fix Danger Zone purge not removing all product attribute taxonomies — now cleans up all orphaned attributes, not just etim_* and skwirrel_variant
1.10.0
- Phased sync architecture — sync now runs in 5 sequential phases (fetch, products, taxonomy, attributes, media) instead of processing everything per product
- Live progress checklist on the sync tab — shows current phase, status icon, and counter (e.g. "247 / 500")
- Performance fix: restore getProducts API call for full sync (faster than getProductsByFilter with empty filter)
- Auto-refresh now only fires on the sync tab, not on other admin pages
1.9.9
- Fix Danger Zone purge silently timing out on large datasets — add set_time_limit(0) to prevent PHP timeout
- Rewrite Danger Zone purge to use bulk SQL — orders of magnitude faster on large stores
1.9.8
- Add "Skwirrel" meta box on product edit screen with single-product sync button
1.9.7
- Add configurable "Product manufacturer base" slug on Settings → Permalinks page
1.9.6
- Fix product sync failing when downloadable files are not in WooCommerce's approved directory
- Downloads/documents errors no longer block category, brand and manufacturer assignment
1.9.5
- Brand sync always active (uses WooCommerce native product_brand taxonomy)
- Add "Sync manufacturers" setting with product_manufacturer taxonomy
- Default product list columns: hide Tags, show Manufacturers
- Add "Filter by manufacturer" dropdown on product list page
- Manufacturers column ordered after Brands, before Date
1.9.3
- Fix variable product variation attributes: recover parent attribute options from child variation post meta when deferred terms are empty
- Convert non-variation parent attributes to global WooCommerce taxonomy-based attributes
- Fix brand not assigned to variable products: propagate brand from child variations to parent
- Fix categories not assigned to variable products: propagate categories from child variations to parent
1.9.2
- Remove legacy pa_variant migration code (no live installs to migrate)
- Fix simple product attributes: save as global WooCommerce taxonomy-based attributes instead of custom text attributes, so they appear in layered navigation and product filters
1.9.1
- Remove legacy pre-1.8.0 Action Scheduler cleanup code (old slug reference)
1.9.0
- Move remaining inline event handlers (onchange, onclick) to enqueued inline script for WordPress.org compliance
- Fix stale debug log path in admin help text
1.8.4
- Add non-variation ETIM and custom class attributes to parent variable products during sync
1.8.3
- Fix empty variation attribute dropdowns on variable products by deferring parent attribute term updates to a single batch flush after all variations are processed
1.8.2
- Replace all inline
<script> and <style> tags with proper wp_enqueue_script/wp_add_inline_script/wp_add_inline_style calls
- Rename plugin display name to "Skwirrel PIM sync for WooCommerce"
1.8.1
- Fix variation attribute labels showing raw ETIM codes (e.g. "EF002671") instead of human-readable names
- Add missing
include_etim_translations and include_languages to getGroupedProducts API call
1.8.0
- Rename plugin slug from
skwirrel-pim-wp-sync to skwirrel-pim-sync (WordPress.org restricts "wp" in plugin slugs)
- Update text domain, Action Scheduler group, logger source, and admin page slug
- Rename main plugin file and all language files to match new slug
- Add activation cleanup for old Action Scheduler group from pre-1.8.0
- Existing settings, synced products, and translations are fully preserved
1.7.1
- Remove deprecated load_plugin_textdomain() call (WordPress 4.6+ auto-loads translations)
- Fix unescaped SQL parameters in purge handler with proper $wpdb->prepare() placeholders
- Fix direct database query caching warning in taxonomy manager
- WordPress Plugin Check compliance improvements
1.7.0
- Slug settings moved to Settings → Permalinks page (alongside WooCommerce product permalinks)
- New "Update slug on re-sync" option: update existing product slugs during sync
- Sync history: new "Trigger" column showing Manual, Scheduled, or Purge
- Purge (delete all) now adds an entry to sync history and preserves last sync status
- Backward compatible slug settings migration from plugin settings to Permalinks page
- New unit tests for slug resolver (16 tests)
- Updated translations (all languages)
1.6.0
- Product slug configuration: choose slug source field (product name, SKU, manufacturer code, external ID, Skwirrel ID)
- Slug suffix on duplicate: configurable fallback field appended when slug already exists
- New class: Slug Resolver for deterministic product URL slugs
1.5.0
- Major refactoring: SyncService split from ~2200 lines into focused sub-classes
- New classes: ProductUpserter, ProductLookup, SyncHistory, PurgeHandler, CategorySync, BrandSync, TaxonomyManager, EtimExtractor, CustomClassExtractor, AttachmentHandler
- SyncService reduced to ~480 lines (pure orchestrator)
- ProductMapper reduced to ~460 lines (delegates to focused sub-classes)
- All existing public APIs preserved — no breaking changes
1.4.0
- Brand sync: Skwirrel brands synced into WooCommerce product_brand taxonomy
- Category tree sync: sync full category tree from a configurable super category ID
- Sync progress indicator: spinning icon on menu item, blue status bar with auto-refresh
- Sync button disabled while sync is in progress
- Heartbeat mechanism: sync status auto-expires after 60s without activity
- Purge: danger zone now also deletes product brands
- Settings save clears sync-in-progress state
- i18n: all UI strings switched to English source text
- Updated translation files (POT + nl_NL, nl_BE, de_DE, fr_FR, fr_BE, en_US, en_GB)
1.3.2
- i18n: all UI strings switched to English source text
- Updated translation files (POT + nl_NL, nl_BE, de_DE, fr_FR, fr_BE, en_US, en_GB)
- Added new translation entries for tabbed UI, custom classes, danger zone and delete protection
- Recompiled all .mo binary translation files
1.3.1
- Deep category tree sync: full ancestor chain from nested _parent_category (unlimited depth)
- Custom Class sync: product-level and trade-item-level custom classes as WooCommerce attributes
- Custom Class feature types: A (alphanumeric), M (multi), L (logical), N (numeric), R (range), D (date), I (internationalized)
- Custom Class text types T and B stored as product meta (skwirrel_cc* prefix)
- Whitelist/blacklist filtering on custom class ID or code
- New settings: sync_custom_classes, sync_trade_item_custom_classes, custom_class_filter_mode, custom_class_filter_ids
1.3.0
- Admin UI: tabbed layout (Sync Products, Instellingen, Logs)
- Sync status and history now shown on the default Sync Products tab
- Sync button moved to page title, visible on all tabs
- Logs and variation debug instructions on dedicated Logs tab
- Fixed GitHub release workflow: version is read from plugin file, no more auto-incrementing
1.2.3
- WordPress Plugin Check compliance: translators comments, ordered placeholders, escape output
- WordPress Plugin Check compliance: phpcs:ignore for direct DB queries, non-prefixed WooCommerce globals, nonce verification
- Use WordPress alternative functions (wp_parse_url, wp_delete_file, wp_is_writable)
- Translate readme.txt to English
1.2.2
- Version bump in preparation for release
1.2.1
- Update text domain and constants for Skwirrel PIM Sync rebranding
1.2.0
- Rebranded to Skwirrel PIM Sync
- Added unit tests for MediaImporter, ProductMapper, and related components
- Added WordPress.org auto-deploy workflow
- Added automated versioning, tagging, and release workflow
1.1.2
- Version bump
- Fix duplicate products during sync: 3-step lookup chain + SKU conflict prevention
1.1.1
- Delete protection: warning banners on Skwirrel-managed products and categories
- Purge stale products and categories after full sync
- Category sync with parent-child hierarchy support
- Collection ID filter for selective synchronisation
- Translation files (POT + nl_NL, nl_BE, en_US, en_GB, de_DE, fr_FR, fr_BE)
- New settings: purge_stale_products, show_delete_warning, collection_ids, sync_categories, include_languages, image_language
- PHPStan, PHP_CodeSniffer, and Pest PHP test framework
- WooCommerce 10.5 compatibility
1.0.0
- Initial release
- Full product synchronisation
- Variable products with ETIM variation axes
- Image and document import
- Delta synchronisation support