{"id":286119,"date":"2026-03-11T22:34:03","date_gmt":"2026-03-11T22:34:03","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/skwirrel-pim-sync\/"},"modified":"2026-03-30T13:55:33","modified_gmt":"2026-03-30T13:55:33","slug":"skwirrel-pim-sync","status":"publish","type":"plugin","link":"https:\/\/kea.wordpress.org\/plugins\/skwirrel-pim-sync\/","author":23459475,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_crdt_document":"","version":"3.2.1","stable_tag":"3.2.1","tested":"6.9.4","requires":"6.0","requires_php":"8.1","requires_plugins":null,"header_name":"Skwirrel PIM sync for WooCommerce","header_author":"Skwirrel B.V.","header_description":"Sync plugin for Skwirrel PIM via Skwirrel JSON-RPC API to WooCommerce.","assets_banners_color":"abce8f","last_updated":"2026-03-30 13:55:33","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/github.com\/Skwirrel-B-V\/skwirrel-pim-sync-for-woocommerce","header_author_uri":"https:\/\/skwirrel.eu","rating":0,"author_block_rating":0,"active_installs":0,"downloads":420,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"2.0.4":{"tag":"2.0.4","author":"jkoomen","date":"2026-03-11 23:05:06"},"2.0.5":{"tag":"2.0.5","author":"jkoomen","date":"2026-03-12 09:02:39"},"2.0.6":{"tag":"2.0.6","author":"jkoomen","date":"2026-03-17 13:26:15"},"2.0.7":{"tag":"2.0.7","author":"jkoomen","date":"2026-03-17 13:27:44"},"2.6.2":{"tag":"2.6.2","author":"jkoomen","date":"2026-03-19 20:44:11"},"3.2.0":{"tag":"3.2.0","author":"jkoomen","date":"2026-03-30 10:36:12"},"3.2.1":{"tag":"3.2.1","author":"jkoomen","date":"2026-03-30 13:55:33"}},"upgrade_notice":[],"ratings":[],"assets_icons":{"icon-128x128.jpg":{"filename":"icon-128x128.jpg","revision":3480706,"resolution":"128x128","location":"assets","locale":""},"icon-256x256.jpg":{"filename":"icon-256x256.jpg","revision":3480706,"resolution":"256x256","location":"assets","locale":""}},"assets_banners":{"banner-1544x500.jpg":{"filename":"banner-1544x500.jpg","revision":3480706,"resolution":"1544x500","location":"assets","locale":""},"banner-772x250.jpg":{"filename":"banner-772x250.jpg","revision":3480706,"resolution":"772x250","location":"assets","locale":""}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["2.0.4","2.0.5","2.0.6","2.0.7","2.6.2","3.2.0","3.2.1"],"block_files":[],"assets_screenshots":[],"screenshots":[],"jetpack_post_was_ever_published":false},"plugin_section":[],"plugin_tags":[175448,42241,257556,1558,286],"plugin_category":[45],"plugin_contributors":[257557],"plugin_business_model":[],"class_list":["post-286119","plugin","type-plugin","status-publish","hentry","plugin_tags-pim","plugin_tags-product-sync","plugin_tags-skwirrel","plugin_tags-sync","plugin_tags-woocommerce","plugin_category-ecommerce","plugin_contributors-jkoomen","plugin_committers-jkoomen"],"banners":{"banner":"https:\/\/ps.w.org\/skwirrel-pim-sync\/assets\/banner-772x250.jpg?rev=3480706","banner_2x":"https:\/\/ps.w.org\/skwirrel-pim-sync\/assets\/banner-1544x500.jpg?rev=3480706","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/skwirrel-pim-sync\/assets\/icon-128x128.jpg?rev=3480706","icon_2x":"https:\/\/ps.w.org\/skwirrel-pim-sync\/assets\/icon-256x256.jpg?rev=3480706","generated":false},"screenshots":[],"raw_content":"<!--section=description-->\n<p>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.<\/p>\n\n<p><strong>Features:<\/strong><\/p>\n\n<ul>\n<li>Full and delta (incremental) product synchronisation<\/li>\n<li>Simple and variable product support with ETIM classification for variation axes<\/li>\n<li>Automatic category tree sync with parent-child hierarchy<\/li>\n<li>Brand sync via WooCommerce native product_brand taxonomy<\/li>\n<li>Manufacturer sync with dedicated product_manufacturer taxonomy<\/li>\n<li>Product image and document import into the WordPress media library<\/li>\n<li>Custom class attributes (alphanumeric, logical, numeric, range, date, multi)<\/li>\n<li>Configurable product URL slugs (source field, suffix, update on re-sync)<\/li>\n<li>GTIN and manufacturer product code search filter on the product list page<\/li>\n<li>Scheduled synchronisation via WP-Cron or Action Scheduler<\/li>\n<li>Manual synchronisation from the admin dashboard with live progress tracking<\/li>\n<li>Date-grouped sync history (last 20 runs)<\/li>\n<li>Stale product and category purge after full sync<\/li>\n<li>Delete protection with warnings and automatic full re-sync<\/li>\n<li>Multilingual support with 7 locales (nl_NL, nl_BE, de_DE, fr_FR, fr_BE, en_US, en_GB)<\/li>\n<\/ul>\n\n<p><strong>Requirements:<\/strong><\/p>\n\n<ul>\n<li>WordPress 6.0 or higher<\/li>\n<li>WooCommerce 8.0 or higher (9.6+ recommended for native brand support; tested up to 10.6)<\/li>\n<li>PHP 8.1 or higher<\/li>\n<li>An active Skwirrel account with API access<\/li>\n<\/ul>\n\n<!--section=installation-->\n<ol>\n<li>Upload the plugin files to <code>\/wp-content\/plugins\/skwirrel-pim-sync\/<\/code>, or install the plugin directly through the WordPress plugin screen.<\/li>\n<li>Activate the plugin through the 'Plugins' screen in WordPress.<\/li>\n<li>Navigate to WooCommerce &gt; Skwirrel Sync to configure the plugin.<\/li>\n<li>Enter your Skwirrel API URL and authentication token.<\/li>\n<li>Click 'Sync now' to start the first synchronisation.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"which%20skwirrel%20api%20version%20is%20supported%3F\"><h3>Which Skwirrel API version is supported?<\/h3><\/dt>\n<dd><p>The plugin works with the Skwirrel JSON-RPC 2.0 API.<\/p><\/dd>\n<dt id=\"how%20often%20are%20products%20synchronised%3F\"><h3>How often are products synchronised?<\/h3><\/dt>\n<dd><p>You can set an automatic schedule (hourly, twice daily, or daily) or synchronise manually from the settings page.<\/p><\/dd>\n<dt id=\"are%20existing%20products%20overwritten%3F\"><h3>Are existing products overwritten?<\/h3><\/dt>\n<dd><p>The plugin uses the Skwirrel external ID as a unique key. Existing products are updated, not duplicated.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>3.2.1<\/h4>\n\n<ul>\n<li>Single-variant groups synced as simple products instead of variable products<\/li>\n<li>Custom features as variation axes alongside ETIM features<\/li>\n<li>Custom feature matching by ID with translated labels<\/li>\n<li>Attribute label auto-update for numeric and cc_ prefixed labels<\/li>\n<li>No duplicate attributes for custom feature variation axes<\/li>\n<li>Phase 3 custom class fetch when grouped products enabled<\/li>\n<\/ul>\n\n<h4>3.2.0<\/h4>\n\n<ul>\n<li>Custom class collection ID \u2014 new required setting for product fetching<\/li>\n<li>Custom classes included in bulk product fetch<\/li>\n<li>Text features (type T) now stored as product attributes<\/li>\n<li>GTIN \/ Variant visibility toggles (default: hidden)<\/li>\n<li>Sync aborts with a clear error when custom class collection ID is not configured<\/li>\n<\/ul>\n\n<h4>3.0.0<\/h4>\n\n<ul>\n<li>Virtual product content \u2014 variable products inherit name, descriptions, categories from virtual products<\/li>\n<li>Variation slugs \u2014 deterministic URL slugs generated from attribute values during sync<\/li>\n<li>Variation permalinks \u2014 optional clean URLs: \/product\/{product-slug}\/{variation-slug}\/<\/li>\n<li>Enhanced Skwirrel meta box \u2014 navigation links between parent and variation products<\/li>\n<li>Theme API \u2014 helper functions for theme developers (variation URLs, thumbnails, default variations)<\/li>\n<li>Example theme snippets in snippets\/ directory<\/li>\n<\/ul>\n\n<h4>2.6.2<\/h4>\n\n<ul>\n<li>Fix false \"not managed by Skwirrel\" message on variable products<\/li>\n<\/ul>\n\n<h4>2.6.1<\/h4>\n\n<ul>\n<li>Fix related products API flag and add smart relation type mapping (auto\/cross-sells\/upsells\/both)<\/li>\n<\/ul>\n\n<h4>2.6.0<\/h4>\n\n<ul>\n<li>Related products sync \u2014 sync Skwirrel related products as WooCommerce cross-sells, upsells, or both<\/li>\n<li>New settings for related products mapping type<\/li>\n<\/ul>\n\n<h4>2.5.0<\/h4>\n\n<ul>\n<li>Variant label setting \u2014 choose which field shows in the variant dropdown (SKU, ERP description, or product name)<\/li>\n<li>Custom class attribute visibility filter \u2014 control which custom class attributes are visible on the product page<\/li>\n<\/ul>\n\n<h4>2.4.4<\/h4>\n\n<ul>\n<li>Fix \"Stop sync\" button \u2014 now checks during phases, not just between them<\/li>\n<li>Show failed sync timestamp and error in status card<\/li>\n<\/ul>\n\n<h4>2.4.3<\/h4>\n\n<ul>\n<li>Flush WooCommerce object cache after every product in all processing phases<\/li>\n<\/ul>\n\n<h4>2.4.2<\/h4>\n\n<ul>\n<li>Flush WordPress object cache between sync phases to reclaim memory<\/li>\n<\/ul>\n\n<h4>2.4.1<\/h4>\n\n<ul>\n<li>Fix OOM in grouped products pre-sync phase \u2014 flush wpdb memory between API pages<\/li>\n<\/ul>\n\n<h4>2.4.0<\/h4>\n\n<ul>\n<li>Deferred attribute fetch \u2014 ETIM and custom classes fetched per-product in attribute phase instead of bulk fetch<\/li>\n<\/ul>\n\n<h4>2.3.5<\/h4>\n\n<ul>\n<li>Aggressive wpdb memory cleanup after every product in all sync phases<\/li>\n<\/ul>\n\n<h4>2.3.4<\/h4>\n\n<ul>\n<li>Fix OOM during fetch \u2014 flush wpdb between batches, default batch size 10<\/li>\n<\/ul>\n\n<h4>2.3.3<\/h4>\n\n<ul>\n<li>Fix OOM during fetch phase \u2014 smaller API batches + wpdb memory flush between pages<\/li>\n<\/ul>\n\n<h4>2.3.2<\/h4>\n\n<ul>\n<li>Fix unexpected output during plugin activation<\/li>\n<\/ul>\n\n<h4>2.3.1<\/h4>\n\n<ul>\n<li>Use WordPress timezone for log filenames instead of UTC<\/li>\n<\/ul>\n\n<h4>2.3.0<\/h4>\n\n<ul>\n<li>Database-backed sync queue \u2014 product data stored in temporary DB table instead of memory, preventing OOM crashes on low-memory servers<\/li>\n<li>Products processed one at a time per phase via cursor pattern (O(1) memory usage)<\/li>\n<\/ul>\n\n<h4>2.2.9<\/h4>\n\n<ul>\n<li>Convert existing simple products to variations when a grouped product sync encounters a duplicate SKU<\/li>\n<li>Reduce memory usage during phased sync by freeing heavy product data after each phase<\/li>\n<\/ul>\n\n<h4>2.2.8<\/h4>\n\n<ul>\n<li>Simplify per-product category assignment \u2014 use resolved map from tree sync instead of recursive per-product resolution<\/li>\n<\/ul>\n\n<h4>2.2.7<\/h4>\n\n<ul>\n<li>Add \"Stop sync\" button to progress banner \u2014 abort a running sync from the dashboard<\/li>\n<li>Log timestamps now respect the WordPress timezone setting<\/li>\n<\/ul>\n\n<h4>2.2.6<\/h4>\n\n<ul>\n<li>Add include_contexts to category API call, improve category sync diagnostics<\/li>\n<\/ul>\n\n<h4>2.2.5<\/h4>\n\n<ul>\n<li>Fix approved download directory: enable existing disabled directories during sync<\/li>\n<\/ul>\n\n<h4>2.2.4<\/h4>\n\n<ul>\n<li>Fix category sync \u2014 use correct API parameter name for fetching categories<\/li>\n<li>Fix per-product category assignment when API returns ID-only category data<\/li>\n<\/ul>\n\n<h4>2.2.3<\/h4>\n\n<ul>\n<li>Dark terminal-style log viewer with syntax highlighting for log levels<\/li>\n<li>JSON objects and sync separators styled for readability<\/li>\n<\/ul>\n\n<h4>2.2.2<\/h4>\n\n<ul>\n<li>Raise PHP memory limit at sync start to prevent OOM crashes on large API responses<\/li>\n<li>Detect fatal errors (OOM) during sync and record them as failed results<\/li>\n<li>Fixes silent sync failures showing stale success status<\/li>\n<\/ul>\n\n<h4>2.2.1<\/h4>\n\n<ul>\n<li>Separate \"Sync Logs\" settings section with per-trigger log mode (per sync or per day)<\/li>\n<li>Add \"Manual (no auto-delete)\" option to log retention<\/li>\n<li>Fix super category ID field width to match selection IDs field<\/li>\n<\/ul>\n\n<h4>2.2.0<\/h4>\n\n<ul>\n<li>Per-sync log files \u2014 each sync run writes to its own log file for easy debugging<\/li>\n<li>Manual syncs get a unique log file; scheduled syncs share a daily log file (appended)<\/li>\n<li>Log viewer modal in sync history \u2014 click \"View\" to read log contents inline<\/li>\n<li>Configurable log retention (12h, 1d, 2d, 7d, 30d) \u2014 old files cleaned up automatically<\/li>\n<\/ul>\n\n<h4>2.1.5<\/h4>\n\n<ul>\n<li>Recursively fetch full category tree from API \u2014 all depth levels are now synced, not just direct children of the super category<\/li>\n<\/ul>\n\n<h4>2.1.4<\/h4>\n\n<ul>\n<li>Auto-register WP uploads directory as WooCommerce approved download directory during sync<\/li>\n<li>Fixes \"downloadable file not in approved folder\" errors for imported PDFs<\/li>\n<\/ul>\n\n<h4>2.1.3<\/h4>\n\n<ul>\n<li>Store Skwirrel API response for all product types: variations and variable product shells now also save _skwirrel_api_response<\/li>\n<\/ul>\n\n<h4>2.1.2<\/h4>\n\n<ul>\n<li>Fix grouped products ignoring dynamic selection ID \u2014 post-filter groups against selection product list<\/li>\n<li>Fetch allowed product IDs from selection before processing groups, skip groups with no matching members<\/li>\n<\/ul>\n\n<h4>2.1.1<\/h4>\n\n<ul>\n<li>Fix grouped products ignoring selection ID filter \u2014 pass dynamic_selection_id to getGroupedProducts<\/li>\n<li>Store raw Skwirrel API response as _skwirrel_api_response post meta during sync<\/li>\n<li>Add dedicated \"Skwirrel API Response\" meta box on the product edit screen showing the stored JSON<\/li>\n<\/ul>\n\n<h4>2.1.0<\/h4>\n\n<ul>\n<li>Selection ID is now required \u2014 sync aborts if no selection ID is configured<\/li>\n<li>Add \"Show API response\" button in the Skwirrel product meta box to view raw JSON from the API<\/li>\n<li>Reduce batch size maximum from 500 to 50, default from 100 to 10<\/li>\n<li>Fix translation: selection ID hint incorrectly said \"category IDs\" in all locales<\/li>\n<\/ul>\n\n<h4>2.0.8<\/h4>\n\n<ul>\n<li>Add raw API response logging for getCategories and per-product _categories data (verbose mode)<\/li>\n<\/ul>\n\n<h4>2.0.7<\/h4>\n\n<ul>\n<li>Fix category tree sync failing when API returns single root category object instead of array<\/li>\n<li>Categories from getCategories are now correctly extracted from root _children when super category ID is used<\/li>\n<\/ul>\n\n<h4>2.0.6<\/h4>\n\n<ul>\n<li>Add diagnostic logging for category-to-product assignment to trace resolution failures<\/li>\n<li>Log each category resolve step (meta lookup, name fallback, creation) when verbose logging is enabled<\/li>\n<li>Warn when categories are extracted from API but no WooCommerce term IDs could be resolved<\/li>\n<li>Check and log wp_set_object_terms errors instead of silently ignoring failures<\/li>\n<\/ul>\n\n<h4>2.0.5<\/h4>\n\n<ul>\n<li>Update README and plugin description to reflect current feature set<\/li>\n<li>Replace \"ERP\/PIM\" references with \"PIM\" throughout<\/li>\n<li>Update WooCommerce minimum to 8.0 (9.6+ recommended for native brand support)<\/li>\n<li>Update WooCommerce tested up to 10.6<\/li>\n<li>Update WordPress tested up to 6.9.4<\/li>\n<\/ul>\n\n<h4>2.0.4<\/h4>\n\n<ul>\n<li>Inline \"Update on re-sync\" toggle in Permalinks section \u2014 saves instantly via AJAX<\/li>\n<li>Slug warning only shown when \"Update on re-sync\" is enabled and settings have changed<\/li>\n<li>Persistent hint when re-sync is enabled warning about URL overwrite and SEO impact<\/li>\n<li>Add batch size hint text (1\u2013500)<\/li>\n<\/ul>\n\n<h4>2.0.3<\/h4>\n\n<ul>\n<li>Add Permalinks section in Settings showing current slug configuration with link to Permalinks page<\/li>\n<li>Show warning when slug settings change, advising a full resync and potential link breakage<\/li>\n<li>Add Selection IDs hint link to Skwirrel selections page (dynamic subdomain URL)<\/li>\n<\/ul>\n\n<h4>2.0.2<\/h4>\n\n<ul>\n<li>Add GTIN \/ Manufacturer product code search filter on product list page<\/li>\n<li>Store product GTIN and manufacturer product code as dedicated meta during sync<\/li>\n<li>Add subtitles to Debug and Danger Zone dashboard blocks<\/li>\n<\/ul>\n\n<h4>2.0.1<\/h4>\n\n<ul>\n<li>Rename \"Collection IDs\" to \"Selection IDs\"<\/li>\n<li>Add API token creation link with dynamic subdomain URL<\/li>\n<li>Add category finder link on Super category ID field<\/li>\n<li>Move WordPress admin notices below the Skwirrel header<\/li>\n<\/ul>\n\n<h4>2.0.0<\/h4>\n\n<ul>\n<li>New admin dashboard with block-grid layout replacing the tab-based UI<\/li>\n<li>Sync progress banner with 6-phase checklist and live counters<\/li>\n<li>Date-grouped sync history table (Today, Yesterday, day name, or date)<\/li>\n<li>Settings page redesigned with grouped fieldsets and Tailwind-inspired styling<\/li>\n<li>Simplified API connection: subdomain-only input with visual prefix\/suffix<\/li>\n<li>Remove auth type selector (always uses static token)<\/li>\n<li>Sync Logs block links directly to WooCommerce logs<\/li>\n<li>Debug and Danger Zone inline in the dashboard grid<\/li>\n<li>Full translation update for all 7 locales (nl_NL, nl_BE, de_DE, fr_FR, fr_BE, en_US, en_GB)<\/li>\n<\/ul>\n\n<h4>1.10.1<\/h4>\n\n<ul>\n<li>Add Domain Path header for automatic translation loading on WordPress 6.7+<\/li>\n<li>Add load_plugin_textdomain() fallback for older WordPress versions<\/li>\n<li>Add nl.mo\/nl.po locale files for sites using \"nl\" instead of \"nl_NL\"<\/li>\n<li>Fix Danger Zone purge not removing all product attribute taxonomies \u2014 now cleans up all orphaned attributes, not just etim_* and skwirrel_variant<\/li>\n<\/ul>\n\n<h4>1.10.0<\/h4>\n\n<ul>\n<li>Phased sync architecture \u2014 sync now runs in 5 sequential phases (fetch, products, taxonomy, attributes, media) instead of processing everything per product<\/li>\n<li>Live progress checklist on the sync tab \u2014 shows current phase, status icon, and counter (e.g. \"247 \/ 500\")<\/li>\n<li>Performance fix: restore getProducts API call for full sync (faster than getProductsByFilter with empty filter)<\/li>\n<li>Auto-refresh now only fires on the sync tab, not on other admin pages<\/li>\n<\/ul>\n\n<h4>1.9.9<\/h4>\n\n<ul>\n<li>Fix Danger Zone purge silently timing out on large datasets \u2014 add set_time_limit(0) to prevent PHP timeout<\/li>\n<li>Rewrite Danger Zone purge to use bulk SQL \u2014 orders of magnitude faster on large stores<\/li>\n<\/ul>\n\n<h4>1.9.8<\/h4>\n\n<ul>\n<li>Add \"Skwirrel\" meta box on product edit screen with single-product sync button<\/li>\n<\/ul>\n\n<h4>1.9.7<\/h4>\n\n<ul>\n<li>Add configurable \"Product manufacturer base\" slug on Settings \u2192 Permalinks page<\/li>\n<\/ul>\n\n<h4>1.9.6<\/h4>\n\n<ul>\n<li>Fix product sync failing when downloadable files are not in WooCommerce's approved directory<\/li>\n<li>Downloads\/documents errors no longer block category, brand and manufacturer assignment<\/li>\n<\/ul>\n\n<h4>1.9.5<\/h4>\n\n<ul>\n<li>Brand sync always active (uses WooCommerce native product_brand taxonomy)<\/li>\n<li>Add \"Sync manufacturers\" setting with product_manufacturer taxonomy<\/li>\n<li>Default product list columns: hide Tags, show Manufacturers<\/li>\n<li>Add \"Filter by manufacturer\" dropdown on product list page<\/li>\n<li>Manufacturers column ordered after Brands, before Date<\/li>\n<\/ul>\n\n<h4>1.9.3<\/h4>\n\n<ul>\n<li>Fix variable product variation attributes: recover parent attribute options from child variation post meta when deferred terms are empty<\/li>\n<li>Convert non-variation parent attributes to global WooCommerce taxonomy-based attributes<\/li>\n<li>Fix brand not assigned to variable products: propagate brand from child variations to parent<\/li>\n<li>Fix categories not assigned to variable products: propagate categories from child variations to parent<\/li>\n<\/ul>\n\n<h4>1.9.2<\/h4>\n\n<ul>\n<li>Remove legacy pa_variant migration code (no live installs to migrate)<\/li>\n<li>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<\/li>\n<\/ul>\n\n<h4>1.9.1<\/h4>\n\n<ul>\n<li>Remove legacy pre-1.8.0 Action Scheduler cleanup code (old slug reference)<\/li>\n<\/ul>\n\n<h4>1.9.0<\/h4>\n\n<ul>\n<li>Move remaining inline event handlers (onchange, onclick) to enqueued inline script for WordPress.org compliance<\/li>\n<li>Fix stale debug log path in admin help text<\/li>\n<\/ul>\n\n<h4>1.8.4<\/h4>\n\n<ul>\n<li>Add non-variation ETIM and custom class attributes to parent variable products during sync<\/li>\n<\/ul>\n\n<h4>1.8.3<\/h4>\n\n<ul>\n<li>Fix empty variation attribute dropdowns on variable products by deferring parent attribute term updates to a single batch flush after all variations are processed<\/li>\n<\/ul>\n\n<h4>1.8.2<\/h4>\n\n<ul>\n<li>Replace all inline <code>&lt;script&gt;<\/code> and <code>&lt;style&gt;<\/code> tags with proper wp_enqueue_script\/wp_add_inline_script\/wp_add_inline_style calls<\/li>\n<li>Rename plugin display name to \"Skwirrel PIM sync for WooCommerce\"<\/li>\n<\/ul>\n\n<h4>1.8.1<\/h4>\n\n<ul>\n<li>Fix variation attribute labels showing raw ETIM codes (e.g. \"EF002671\") instead of human-readable names<\/li>\n<li>Add missing <code>include_etim_translations<\/code> and <code>include_languages<\/code> to <code>getGroupedProducts<\/code> API call<\/li>\n<\/ul>\n\n<h4>1.8.0<\/h4>\n\n<ul>\n<li>Rename plugin slug from <code>skwirrel-pim-wp-sync<\/code> to <code>skwirrel-pim-sync<\/code> (WordPress.org restricts \"wp\" in plugin slugs)<\/li>\n<li>Update text domain, Action Scheduler group, logger source, and admin page slug<\/li>\n<li>Rename main plugin file and all language files to match new slug<\/li>\n<li>Add activation cleanup for old Action Scheduler group from pre-1.8.0<\/li>\n<li>Existing settings, synced products, and translations are fully preserved<\/li>\n<\/ul>\n\n<h4>1.7.1<\/h4>\n\n<ul>\n<li>Remove deprecated load_plugin_textdomain() call (WordPress 4.6+ auto-loads translations)<\/li>\n<li>Fix unescaped SQL parameters in purge handler with proper $wpdb-&gt;prepare() placeholders<\/li>\n<li>Fix direct database query caching warning in taxonomy manager<\/li>\n<li>WordPress Plugin Check compliance improvements<\/li>\n<\/ul>\n\n<h4>1.7.0<\/h4>\n\n<ul>\n<li>Slug settings moved to Settings \u2192 Permalinks page (alongside WooCommerce product permalinks)<\/li>\n<li>New \"Update slug on re-sync\" option: update existing product slugs during sync<\/li>\n<li>Sync history: new \"Trigger\" column showing Manual, Scheduled, or Purge<\/li>\n<li>Purge (delete all) now adds an entry to sync history and preserves last sync status<\/li>\n<li>Backward compatible slug settings migration from plugin settings to Permalinks page<\/li>\n<li>New unit tests for slug resolver (16 tests)<\/li>\n<li>Updated translations (all languages)<\/li>\n<\/ul>\n\n<h4>1.6.0<\/h4>\n\n<ul>\n<li>Product slug configuration: choose slug source field (product name, SKU, manufacturer code, external ID, Skwirrel ID)<\/li>\n<li>Slug suffix on duplicate: configurable fallback field appended when slug already exists<\/li>\n<li>New class: Slug Resolver for deterministic product URL slugs<\/li>\n<\/ul>\n\n<h4>1.5.0<\/h4>\n\n<ul>\n<li>Major refactoring: SyncService split from ~2200 lines into focused sub-classes<\/li>\n<li>New classes: ProductUpserter, ProductLookup, SyncHistory, PurgeHandler, CategorySync, BrandSync, TaxonomyManager, EtimExtractor, CustomClassExtractor, AttachmentHandler<\/li>\n<li>SyncService reduced to ~480 lines (pure orchestrator)<\/li>\n<li>ProductMapper reduced to ~460 lines (delegates to focused sub-classes)<\/li>\n<li>All existing public APIs preserved \u2014 no breaking changes<\/li>\n<\/ul>\n\n<h4>1.4.0<\/h4>\n\n<ul>\n<li>Brand sync: Skwirrel brands synced into WooCommerce product_brand taxonomy<\/li>\n<li>Category tree sync: sync full category tree from a configurable super category ID<\/li>\n<li>Sync progress indicator: spinning icon on menu item, blue status bar with auto-refresh<\/li>\n<li>Sync button disabled while sync is in progress<\/li>\n<li>Heartbeat mechanism: sync status auto-expires after 60s without activity<\/li>\n<li>Purge: danger zone now also deletes product brands<\/li>\n<li>Settings save clears sync-in-progress state<\/li>\n<li>i18n: all UI strings switched to English source text<\/li>\n<li>Updated translation files (POT + nl_NL, nl_BE, de_DE, fr_FR, fr_BE, en_US, en_GB)<\/li>\n<\/ul>\n\n<h4>1.3.2<\/h4>\n\n<ul>\n<li>i18n: all UI strings switched to English source text<\/li>\n<li>Updated translation files (POT + nl_NL, nl_BE, de_DE, fr_FR, fr_BE, en_US, en_GB)<\/li>\n<li>Added new translation entries for tabbed UI, custom classes, danger zone and delete protection<\/li>\n<li>Recompiled all .mo binary translation files<\/li>\n<\/ul>\n\n<h4>1.3.1<\/h4>\n\n<ul>\n<li>Deep category tree sync: full ancestor chain from nested _parent_category (unlimited depth)<\/li>\n<li>Custom Class sync: product-level and trade-item-level custom classes as WooCommerce attributes<\/li>\n<li>Custom Class feature types: A (alphanumeric), M (multi), L (logical), N (numeric), R (range), D (date), I (internationalized)<\/li>\n<li>Custom Class text types T and B stored as product meta (<em>skwirrel_cc<\/em>* prefix)<\/li>\n<li>Whitelist\/blacklist filtering on custom class ID or code<\/li>\n<li>New settings: sync_custom_classes, sync_trade_item_custom_classes, custom_class_filter_mode, custom_class_filter_ids<\/li>\n<\/ul>\n\n<h4>1.3.0<\/h4>\n\n<ul>\n<li>Admin UI: tabbed layout (Sync Products, Instellingen, Logs)<\/li>\n<li>Sync status and history now shown on the default Sync Products tab<\/li>\n<li>Sync button moved to page title, visible on all tabs<\/li>\n<li>Logs and variation debug instructions on dedicated Logs tab<\/li>\n<li>Fixed GitHub release workflow: version is read from plugin file, no more auto-incrementing<\/li>\n<\/ul>\n\n<h4>1.2.3<\/h4>\n\n<ul>\n<li>WordPress Plugin Check compliance: translators comments, ordered placeholders, escape output<\/li>\n<li>WordPress Plugin Check compliance: phpcs:ignore for direct DB queries, non-prefixed WooCommerce globals, nonce verification<\/li>\n<li>Use WordPress alternative functions (wp_parse_url, wp_delete_file, wp_is_writable)<\/li>\n<li>Translate readme.txt to English<\/li>\n<\/ul>\n\n<h4>1.2.2<\/h4>\n\n<ul>\n<li>Version bump in preparation for release<\/li>\n<\/ul>\n\n<h4>1.2.1<\/h4>\n\n<ul>\n<li>Update text domain and constants for Skwirrel PIM Sync rebranding<\/li>\n<\/ul>\n\n<h4>1.2.0<\/h4>\n\n<ul>\n<li>Rebranded to Skwirrel PIM Sync<\/li>\n<li>Added unit tests for MediaImporter, ProductMapper, and related components<\/li>\n<li>Added WordPress.org auto-deploy workflow<\/li>\n<li>Added automated versioning, tagging, and release workflow<\/li>\n<\/ul>\n\n<h4>1.1.2<\/h4>\n\n<ul>\n<li>Version bump<\/li>\n<li>Fix duplicate products during sync: 3-step lookup chain + SKU conflict prevention<\/li>\n<\/ul>\n\n<h4>1.1.1<\/h4>\n\n<ul>\n<li>Delete protection: warning banners on Skwirrel-managed products and categories<\/li>\n<li>Purge stale products and categories after full sync<\/li>\n<li>Category sync with parent-child hierarchy support<\/li>\n<li>Collection ID filter for selective synchronisation<\/li>\n<li>Translation files (POT + nl_NL, nl_BE, en_US, en_GB, de_DE, fr_FR, fr_BE)<\/li>\n<li>New settings: purge_stale_products, show_delete_warning, collection_ids, sync_categories, include_languages, image_language<\/li>\n<li>PHPStan, PHP_CodeSniffer, and Pest PHP test framework<\/li>\n<li>WooCommerce 10.5 compatibility<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>Initial release<\/li>\n<li>Full product synchronisation<\/li>\n<li>Variable products with ETIM variation axes<\/li>\n<li>Image and document import<\/li>\n<li>Delta synchronisation support<\/li>\n<\/ul>","raw_excerpt":"Synchronises products from the Skwirrel PIM system to WooCommerce via a JSON-RPC 2.0 API.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/kea.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/286119","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/kea.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/kea.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/kea.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=286119"}],"author":[{"embeddable":true,"href":"https:\/\/kea.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/jkoomen"}],"wp:attachment":[{"href":"https:\/\/kea.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=286119"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/kea.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=286119"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/kea.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=286119"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/kea.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=286119"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/kea.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=286119"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/kea.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=286119"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}