Dalibor Votruba e3464525a8 Catch pre-v1.6.1 attachments in image dedup — v1.7.2 1 bulan lalu
..
assets e3464525a8 Catch pre-v1.6.1 attachments in image dedup — v1.7.2 1 bulan lalu
includes e3464525a8 Catch pre-v1.6.1 attachments in image dedup — v1.7.2 1 bulan lalu
languages 4b7132cf5f regenerate .mo file 1 bulan lalu
views 184e7b8ec3 Phase A — safety & robustness pass — v1.6.2 1 bulan lalu
.gitignore 20a8c110ab Serve admin assets under version-stamped filenames for cache busting 1 bulan lalu
CLAUDE.md e3464525a8 Catch pre-v1.6.1 attachments in image dedup — v1.7.2 1 bulan lalu
directory-structure.txt 39b3136909 Convert Category Manipulations page to lazy-loaded tabs — v1.6.0 1 bulan lalu
fix-multi-image-plan-00.md bf114cd86e Add analysis and implementation plan for product-image dedup (v1.6.1) 1 bulan lalu
fix-multi-image-plan-01.md bf114cd86e Add analysis and implementation plan for product-image dedup (v1.6.1) 1 bulan lalu
implementation-plan-tabs.md c893e8267a Add implementation plan for tabbed Category Manipulations page (v1.6.0) 1 bulan lalu
inplementation-plan-upvp.md 29ec819be6 Add UPVP implementation plan for v1.5.3 2 bulan lalu
instructions.txt e573694268 Add Remove Not Assigned Media feature, fix physical file deletion — v1.5.2 3 bulan lalu
readme.md e3464525a8 Catch pre-v1.6.1 attachments in image dedup — v1.7.2 1 bulan lalu
studiou-wc-product-cat-manage.php e3464525a8 Catch pre-v1.6.1 attachments in image dedup — v1.7.2 1 bulan lalu

readme.md

QDR - Studiou WC Export/Import Product Categories

Version: 1.7.2

A WordPress plugin that extends WooCommerce to provide batch export and import functionality for both product categories and products, along with category manipulation tools.

Description

QDR - Studiou WC Export/Import Product Categories is a powerful WordPress plugin for WooCommerce store administrators who need to manage product categories and products in bulk. This plugin allows you to:

  • Export and import product categories with all their settings
  • Export and import variable products and their variations
  • Manipulate categories (move products, batch update descriptions, delete products)
  • Support for WooCommerce Protected Categories extension

The plugin provides a complete solution for bulk product and category management with comprehensive validation, error reporting, and progress tracking.

Features

Category Management

  • Export all product categories to a CSV file
  • Import product categories from a CSV file
  • Add, update, or delete product categories in batch
  • Support for WooCommerce Protected Categories visibility settings
  • Move products between categories in bulk
  • Batch description update for multiple categories
  • Delete products in category - permanently delete all products and variants from selected categories
  • Clear Media Categories - permanently delete all media files from selected media categories (NEW in v1.5)
  • Remove Not Assigned Media - permanently delete all unused uncategorized media files (NEW in v1.5.2)
  • Update product variant prices - bulk-update regular price of variations by category + attribute filter (NEW in v1.5.3)
  • Tabbed Category Manipulations page - each operation is a tab whose content loads on demand, preventing page-load timeouts on large stores (NEW in v1.6.0)

Product Management (NEW in v1.4)

  • Export products to CSV - Export variable products and variations by category selection
  • Import products from CSV - Batch create/update variable products and variations
  • Full support for product attributes and variations
  • Image URL handling with validation
  • Min/Max quantity support
  • Comprehensive import rules with validation
  • Failed products download for retry

General Features

  • User-friendly interface integrated with WooCommerce admin
  • Real-time progress tracking for bulk operations
  • Comprehensive validation and error reporting
  • Full translation support (English/Czech)

Requirements

  • WordPress 6.8.1 or higher
  • PHP 8.2 or higher
  • WooCommerce 9.8 or higher
  • WooCommerce Protected Categories 2.7 or higher

Installation

  1. Download the plugin ZIP file
  2. Go to WordPress Dashboard > Plugins > Add New
  3. Click "Upload Plugin" and select the ZIP file
  4. Click "Install Now"
  5. Activate the plugin

CSV Formats

Product Category CSV Format

The plugin uses CSV files with the following columns for categories:

Column Description
name Product Category Name
url-name Product Category URL slug
parent-name Parent Product Category Name (empty if no parent)
description Product Category description
display-type Product Category display type (values: 'default', 'products', 'subcategories', 'both')
visibility Product Category visibility (values: 'public', 'protected')
protected-passwords Pipe (|) separated passwords if visibility is 'protected'
operation Record operation: 'A' - add, 'U' - update, 'D' - delete

Product CSV Format (NEW in v1.4)

The plugin uses CSV files with the following columns for products:

Column Description
ID Product ID (0 for new products)
Typ Product type (only "variable" or "variation" allowed)
Katalogové číslo SKU (must be unique)
Jméno Product name
Nadřazené Parent product SKU (for variations only)
Krátký popis Short description
Popis Description
Název 1 vlastnosti Attribute 1 name
Hodnota(y) 1 vlastnosti Attribute 1 value(s) (pipe-separated for variable products)
Kategorie Categories (pipe-separated)
Obrázky Image URL (must be valid and accessible)
Běžná cena Regular price (required for variations)
Vlastnost 1 viditelnost Attribute 1 visibility (1 or 0)
Vlastnost 1 globální Attribute 1 global (1 or 0)
Vlastnost 1 varianta Attribute 1 used for variations (1 or 0)
Povolit zákaznické recenze? Enable reviews (1 or 0)
Minimum Quantity Minimum order quantity
Maximum Quantity Maximum order quantity

Usage

Exporting Product Categories

  1. Go to Products > Export Product Categories
  2. Click "Export Product Categories"
  3. Download the generated CSV file

Importing Product Categories

  1. Go to Products > Import Product Categories
  2. Select your CSV file
  3. Click "Import Product Categories"
  4. Review the import results

Exporting Products (NEW in v1.4)

  1. Go to Products > Product Export
  2. Select categories using checkboxes
    • Use "Select All" to select all categories
    • Use "Deselect All" to deselect all categories
  3. Click "Export Selected Products"
  4. Download the generated CSV file

Importing Products (NEW in v1.4)

  1. Go to Products > Product Import
  2. Select your CSV file (UTF-8 encoding)
  3. Click "Process Import File"
  4. Watch the progress bar as products are being imported in batches
    • Products are processed 5 at a time to avoid timeout issues
    • Progress shows "Processing: X / Y products"
  5. Review the import results showing:
    • Successful imports
    • Failed imports
    • Skipped items
    • Detailed messages for skipped/failed items only
  6. If there are failed items, click "Save Failed Products" to download a CSV file with failed items for correction and re-import

Product Import Features:

  • Batch Processing: Processes 5 products per batch to avoid PHP timeouts
  • Auto-Create Categories: Missing categories are automatically created during import
  • Real-Time Progress: Shows exact progress (e.g., "Processing: 15 / 50 products")
  • Smart Category Matching: Tries exact name, slug, and case-insensitive matching
  • Image Optimization: 30-second timeout per image, intermediate sizes disabled for speed
  • Detailed Logging: All operations logged for debugging (prefix: "STUDIOU WC IMPORT:")

Product Import Rules:

  • Rule 1: All operations performed via WooCommerce API (not direct SQL)
  • Rule 2: If ID = 0, item will be created; otherwise updated
  • Rule 3: Only "variable" or "variation" types are allowed
  • Rule 4: SKU (Katalogové číslo) must be unique in WooCommerce database
  • Rule 5: Image URL must be valid format (accessibility checked during download)
  • Rule 6: Parent reference (Nadřazené) must point to an existing variable product SKU
  • Rule 7: Variations must have a regular price (Běžná cena)

Important Notes:

  • Categories have unique names throughout the system (no hierarchy path needed)
  • Category names can contain dashes, dots, and special characters
  • Failed image downloads don't stop the import, they're just logged
  • Import can handle large files thanks to batch processing

Category Manipulations

Moving Products Between Categories

  1. Go to Products > Category Manipulations
  2. Select the source category (from which products will be moved)
  3. Select the target category (to which products will be moved)
  4. Click "Do" to execute the move operation
  5. Review the results showing how many products were moved

Important Notes about Moving Products:

  • Products can be assigned to multiple categories. This operation will remove the product from the source category and add it to the target category.
  • If a product is only assigned to the source category, it will be moved entirely to the target category.
  • If a product is assigned to multiple categories including the source category, it will remain in the other categories and be moved to the target category.
  • The operation processes all products regardless of their status (published, draft, private).

Batch Description Between Categories

  1. Go to Products > Category Manipulations
  2. Scroll to the "Batch description between categories" section
  3. Select one or more categories using the checkboxes
    • Use "Check All" to select all categories
    • Use "Uncheck All" to deselect all categories
  4. Enter the description text in the textarea
  5. Click "Do" to apply the description to all selected categories
  6. Review the results showing how many categories were updated

Important Notes about Batch Description:

  • The operation will overwrite the existing descriptions for all selected categories
  • Categories can be selected individually or in bulk using the check/uncheck all buttons
  • The description field supports multi-line text
  • All selected categories will receive exactly the same description

Delete Products in Category

  1. Go to Products > Category Manipulations
  2. Scroll to the "Delete products in category" section
  3. Select one or more categories using the checkboxes
    • Use "Check All" to select all categories
    • Use "Uncheck All" to deselect all categories
  4. Click "Delete" button (you will be asked to confirm)
  5. Watch the progress bar as products are being deleted in batches
  6. Review the deletion statistics showing:
    • Total products deleted
    • Failed deletions (if any)
    • Failed product IDs (if any)

Important Notes about Delete Products:

  • THIS OPERATION PERMANENTLY DELETES ALL PRODUCTS AND THEIR VARIANTS from the selected categories
  • THIS ACTION CANNOT BE UNDONE!
  • Products are deleted using WooCommerce operations to ensure proper cleanup
  • Variable products will have all their variations deleted automatically
  • Products are processed in batches of 10 to prevent timeouts
  • A real-time progress bar shows the deletion progress
  • If a product belongs to multiple categories, it will still be deleted entirely from the system
  • The page will automatically reload after successful deletion to update category counts

Clear Media Categories (NEW in v1.5)

  1. Go to Products > Category Manipulations
  2. Scroll to the "Clear Media Categories" section
  3. Select one or more media categories using the checkboxes
    • Use "Check All" to select all media categories
    • Use "Uncheck All" to deselect all media categories
  4. Click "Delete" button (you will be asked to confirm)
  5. Watch the progress bar as media files are being deleted in batches
  6. Review the deletion statistics showing:
    • Total media files deleted
    • Failed deletions (if any)
    • Failed media IDs (if any)

Important Notes about Clear Media Categories:

  • THIS OPERATION PERMANENTLY DELETES ALL MEDIA FILES from the selected media categories
  • The files will be removed from the server. THIS ACTION CANNOT BE UNDONE!
  • Requires a media category plugin (e.g., Media Library Categories) to be installed
  • Media files are deleted using wp_delete_attachment() for proper cleanup
  • Media files are processed in batches of 10 to prevent timeouts
  • A real-time progress bar shows the deletion progress
  • The page will automatically reload after successful deletion to update category counts

Remove Not Assigned Media (NEW in v1.5.2)

  1. Go to Products > Category Manipulations
  2. Scroll to the "Remove Not Assigned Media" section
  3. The button shows the count of unused uncategorized media files
  4. Click "Delete unused uncategorized media (N)" button (you will be asked to confirm)
  5. Watch the progress bar as media files are being deleted in batches
  6. Review the deletion statistics

What counts as "unused uncategorized media":

  • Not assigned to any media category
  • Not used as a featured image for any post or product
  • Not used in any WooCommerce product image gallery
  • Not attached to any post (post_parent = 0)

Important Notes about Remove Not Assigned Media:

  • THIS OPERATION PERMANENTLY DELETES MEDIA FILES that meet all criteria above
  • The files will be removed from the server. THIS ACTION CANNOT BE UNDONE!
  • Media files are processed in batches of 10 to prevent timeouts
  • Both the WordPress attachment post and the physical files (including thumbnails) are deleted
  • A real-time progress bar shows the deletion progress
  • The page will automatically reload after successful deletion to update the count

Update Product Variant Prices (NEW in v1.5.3)

  1. Go to Products > Category Manipulations
  2. Scroll to the "Update product variant prices" section
  3. Select one or more product categories using the checkboxes
    • Use "Check All" to select all categories
    • Use "Uncheck All" to deselect all categories
  4. Pick a Variant attribute from the dropdown (heads such as Color, Size — populated from variation-eligible attributes in the store)
  5. Pick a Variant attribute value from the dropdown (values are scoped to the chosen attribute and selected categories)
  6. Enter the New Price
  7. Watch the Affected variations label — it updates live as you change filters
  8. Click Dry Run to preview the count and a sample of variations that would be updated (no DB writes)
  9. Click Apply to commit the new regular price; you will be asked to confirm
  10. Review the results showing updated / failed counts and any failed variation IDs

Important Notes about Update Product Variant Prices:

  • The operation modifies only the regular_price of product_variation records
  • Order line items, cart contents, and historical order data are never modified — past orders keep their original prices
  • All updates go through the WooCommerce API (set_regular_price + WC_Product_Variable::sync on the parent variable products)
  • Parent variable products are re-synced after the batch so the storefront price-range cache stays correct
  • Always run Dry Run first to verify the affected count
  • If a variation belongs to a non-variable parent (orphan), it is counted as failed and listed in the result

Sample CSVs

Sample Product Category CSV

name,url-name,parent-name,description,display-type,visibility,protected-passwords,operation
"Clothing","clothing","","Top quality clothing","default","public","","A"
"Men","men","Clothing","Men's clothing","products","public","","A"
"Women","women","Clothing","Women's clothing","products","protected","password123","A"
"Kids","kids","Clothing","Kids clothing","products","public","","U"
"Accessories","accessories","","All accessories","default","public","","D"

Category Import Operations:

  • A - Add a new product category
  • U - Update an existing product category (identified by name)
  • D - Delete an existing product category (identified by name)

Sample Product CSV (NEW in v1.4)

ID,Typ,Katalogové číslo,Jméno,Nadřazené,Krátký popis,Popis,Název 1 vlastnosti,Hodnota(y) 1 vlastnosti,Kategorie,Obrázky,Běžná cena,Vlastnost 1 viditelnost,Vlastnost 1 globální,Vlastnost 1 varianta,Povolit zákaznické recenze?,Minimum Quantity,Maximum Quantity
0,variable,T-SHIRT-001,"Basic T-Shirt","","Comfortable cotton t-shirt","High-quality cotton t-shirt in various sizes",Size,"S|M|L|XL","Clothing|Men","https://example.com/tshirt.jpg","",1,1,1,1,1,10
0,variation,T-SHIRT-001-S,"Basic T-Shirt - S",T-SHIRT-001,"","",Size,S,"","https://example.com/tshirt-s.jpg",19.99,0,1,0,0,1,10
0,variation,T-SHIRT-001-M,"Basic T-Shirt - M",T-SHIRT-001,"","",Size,M,"","https://example.com/tshirt-m.jpg",19.99,0,1,0,0,1,10

Menu Structure

After activation, the plugin adds the following menu items under Products in the WordPress admin:

Category Management

  • Import Product Categories
  • Export Product Categories
  • Category Manipulations
    • Move products between categories
    • Batch description between categories
    • Delete products in category
    • Clear Media Categories (NEW in v1.5)
    • Remove Not Assigned Media (NEW in v1.5.2)
    • Update product variant prices (NEW in v1.5.3)
    • Update product variant prices (NEW in v1.5.3)

Product Management (NEW in v1.4)

  • Product Import - Batch import variable products and variations
  • Product Export - Export products by category selection

License

GPL v2 or later - https://www.gnu.org/licenses/gpl-2.0.html

Author

Dalibor Votruba
Website: Quadarax

Support

For support, please visit https://www.quadarax.com/plugins/studiou-wc-product-cat-manage

Changelog

Version 1.7.2

  • Product import: dedup now also catches images that were imported before v1.6.1. The v1.6.1 dedup matched only attachments tagged with the _studiou_wcpcm_source_url postmeta — fine for anything imported via the dedup-aware code, but a re-import of a product whose image was already in the Media Library from an older import (or uploaded manually) would still sideload a duplicate (<name>-1.jpg). The matcher now falls back to matching _wp_attached_file against the uploads-relative path derived from the URL (URL path minus the configured uploads baseurl path, URL-decoded). When the fallback hits, the matched attachment is backfilled with _studiou_wcpcm_source_url so the next import of the same URL takes the precise O(1) path. Order of precedence is unchanged: in-request static cache → _studiou_wcpcm_source_url exact match → fallback by uploads-relative path → fresh sideload.

Version 1.7.1

  • Performance: category counts in the manipulation dropdowns are now a single aggregate query (M9). Previously the manipulator looped over every product category and ran a separate COUNT(DISTINCT) query for each, which the 5-minute transient cache masked — but the cache is busted by every set_object_terms / edited_term / etc., which this plugin's own bulk operations fire constantly, so the per-category loop ran often. Replaced with one GROUP BY query that preserves the existing post_type = 'product' and post_status IN (publish, private, draft) filters via the ON clause, so trashed and pending products don't inflate the displayed counts. Zero-count categories still appear (LEFT JOIN). Cache layer unchanged.
  • Product import: per-request cache for the full product_cat term list (M8). The case-insensitive fallback inside find_or_create_category_by_name (still aliased as find_category_by_name for compat) used to call get_terms() on every miss-path row — O(N) categories per miss, O(N*M) overall. Now loaded once per AJAX request and reused; newly created terms append into the cache. Method renamed to make the "creates as a side effect" behaviour visible at call sites.
  • Product import: success-row logs are now gated behind WP_DEBUG (M7). "Processing categories for product X", "Categories assigned via set_category_ids()", "find_category_by_name called for Y", "Found by exact name match - ID Z", and similar success/info lines no longer flood the production PHP error log on every import. Failure-path logs (creation failed, term insert failed, image download failed, etc.) stay always-on. Matches the documented "Only logs failures" policy.
  • Product export row count is now correct when fields contain newlines (L2). The old substr_count($csv_content, "\n") - 1 over-counted whenever a product description contained a newline. export_products() now accumulates the count during generation and returns it via a by-ref parameter.
  • Runtime-generated versioned asset copies moved out of the plugin directory and into uploads/studiou-wcpcm-cache/ (L4). Generating versioned admin-X.Y.Z.js / admin-X.Y.Z.css files inside the plugin directory tripped some security scanners and failed on managed hosts with read-only plugin dirs. The new location is the writable WordPress uploads dir; the cache subdirectory gets index.php silence files. The plugin dir is left untouched.
  • UPVP: detects and reports variations whose sale price ends up greater than the new regular price (L7). When the operator sets a new regular price below an existing sale price (sale > regular is invalid), the operation now logs STUDIOU WC UPVP: variation N has sale_price S greater than new regular_price R per affected variation and includes a sale_warnings array in the AJAX response. The plugin does not auto-clamp the sale price — sale data is operator-owned — but the warning gives the operator the information needed to fix it.
  • Security & operational notes documented in CLAUDE.md (L6, L8). Server-side image fetching (SSRF surface gated by manage_woocommerce) and the failed-CSV retry being creation-only are both called out under a new "Security notes" section.
  • Two legacy single-shot AJAX actions from prior versions (studiou_wcpcm_import, studiou_wcpcm_move_products) remain registered for backwards compatibility. The bundled UI no longer calls them.

Version 1.7.0

  • Category import is now batched and disk-staged (M1, M4 rework). The legacy single-shot endpoint that processed the entire CSV in one AJAX call ran into the ~60 second PHP timeout on stores with thousands of categories. The new flow mirrors the product importer: the parse step stages rows to a guarded wp-content/uploads/studiou-wcpcm-staging/<token>.json file (index.php + .htaccess guards, 24-hour TTL); the batch step processes 10 rows per AJAX call and reports progress; the JS controller polls until done. Two new AJAX actions: studiou_wcpcm_import_parse, studiou_wcpcm_import_batch. The legacy studiou_wcpcm_import action is still registered for backwards compatibility but is no longer used by the bundled UI.
  • Product move is now batched (M2). Same shape as the existing delete-products flow: a studiou_wcpcm_move_products_start action returns the source category's product IDs, then studiou_wcpcm_move_products_chunk moves 25 at a time. wp_set_post_terms is idempotent, so a retried chunk after a network blip won't corrupt anything. The single-shot studiou_wcpcm_move_products action remains for backwards compatibility.
  • Product import no longer uses a WordPress transient to stage CSV rows (M4 rework). The transient was a single wp_options row; large imports overflowed max_allowed_packet and surfaced as the misleading "Import data not found or expired". The new disk-streaming staging (shared with the category importer) has no such ceiling. The 1.6.2 transient-failure guard becomes unnecessary but remains as a defensive error path on the new disk write.
  • Two new helper static methods on Studiou_WC_Product_Manage_Product_Import (get_staging_dir, stage_rows, read_stage_slice, delete_stage, prune_staging) are the shared staging API used by both importers.

Version 1.6.4

  • Security: gated product-export download. Previously the product exporter dropped product-export-YYYY-MM-DD-H-i-s.csv into wp-content/uploads/studiou-wc-product-exports/ and returned the raw public URL — anyone who knew or guessed the timestamped name could download the file, and the directory was never cleaned. Now mirrors the category exporter:
    • Export files live in wp-content/uploads/studiou-wcpcm-product-exports/ with index.php and .htaccess guards.
    • Filenames embed a 32-character random hex token (product-export-<32hex>.csv) so the path is unguessable even if directory listing leaks.
    • Downloads now route through admin-init with a nonce check, a manage_woocommerce capability check, a strict regex on the requested basename, and a realpath confinement check that defends against path traversal and symlink escape.
    • Every new export prunes files older than 24 hours so the directory doesn't grow without bound.

Version 1.6.3

  • Product import: correct round-trip for taxonomy and custom attributes. The importer now reads the Vlastnost 1 globální column (previously written by the exporter but never consumed) and branches on it:
    • Global / taxonomy attribute (globální = 1): the importer registers the taxonomy, resolves each Hodnota(y) 1 vlastnosti value to its term (creating the term via wp_insert_term if it doesn't exist), passes the term IDs to WC_Product_Attribute::set_options(), and links the terms to the product via wp_set_object_terms after save. For variations the importer stores the term slug (not the raw name) under the attribute_pa_* meta key, so WooCommerce can match the customer's selection on the storefront. Previously the importer passed raw names to set_options() and stored raw names in variation meta, which meant taxonomy variations were unreachable ("No matching variation").
    • Custom (product-level) attribute (globální = 0 or column absent): the importer now correctly creates a non-taxonomy WC_Product_Attribute with set_id(0) and a plain display name, stores the raw values, and writes variation meta under attribute_<sanitized name>. Previously every attribute was force-converted to a pa_* taxonomy, polluting the store with global taxonomies for what was meant to be a product-level attribute.
  • Live-test gate before deployment. Per the master plan §5.B.0, verify on a real WooCommerce install before shipping: create a variable product with a global pa_* attribute and 2-3 variations, export, delete, re-import the export, then storefront-test that each variation is selectable. The fix is shaped from the review's analysis; the live test is what proves it.

Version 1.6.2

  • Safety: "Remove Not Assigned Media" no longer destroys WooCommerce product-category images. The "unused" attachment query now also excludes any attachment referenced from termmeta thumbnail_id (the WC category-image convention) and the customizer (custom logo, site icon, header image). NOTE: this narrows the blast radius; it does not make the operation safe in general. Images embedded only in post / page / product content HTML, in ACF/meta fields, in custom termmeta keys other than thumbnail_id, and in WooCommerce downloadable-product files are still NOT detected and will still be deleted if you click the button. The tab warning has been rewritten to say so explicitly. The preview-list UI that actually closes the gap is a separate change tracked under review-00-plan-02.
  • Product import: ragged CSV rows no longer crash the entire import. On PHP 8+ array_combine throws ValueError (which extends Error, not Exception) when a row's column count doesn't match the header. The surrounding catch (Exception) missed it and the whole import died as a bare 500. Now: short rows are padded with empty cells (Excel trailing-comma artifact, recoverable); over-long rows are skipped with a clear "column count mismatch" reason and surface in the failed-CSV download. All product import / export handlers' catches widened from Exception to \Throwable.
  • Product import: strip UTF-8 BOM on parse. Excel commonly saves CSV with a leading BOM. Without this fix the first header became "\xEF\xBB\xBFID", every row missed the ID key, every product was treated as new, and most then got skipped on SKU-uniqueness. Matches what the category importer has always done. For symmetry, the product export now also writes a BOM (Policy A: write BOM in exports, strip BOM on import) so an Excel round-trip is lossless.
  • Product import: large CSVs that overflow the WordPress transient store now report a clear, actionable error instead of the misleading downstream "Import data not found or expired". The structural fix that actually removes the size ceiling (disk-streaming staging) lands in 1.7.0.
  • Category import update operation no longer silently re-parents children to root. Previously, any U row with a blank parent-name would set parent = 0, which silently moved every child being updated up to root. Now: blank parent-name on a U row leaves the existing parent untouched. To explicitly move a child to root, set parent-name to the literal sentinel __ROOT__. A (add) rows keep blank = root, since a new category has no existing parent to preserve.
  • Plugin header WC requires at least corrected from 9.0 to 9.8 to match the runtime check and the documented requirement.

Version 1.6.1

  • Product import: deduplicate media by source URL - a single Obrázky URL is now downloaded once per import (and once per re-import), and every row that references it - the variable parent and all its variations - reuses the same attachment ID. Eliminates the image-1.jpg, image-2.jpg, ... clutter that previously appeared in wp-content/uploads/, and stops each variation from pointing at its own private copy of what is logically the parent's image.
  • New attachment postmeta _studiou_wcpcm_source_url records the trimmed source URL for every image this importer brings in, so dedup survives across batches and across re-imports months later. A per-request in-memory cache absorbs repeats within a single AJAX batch.
  • The on-disk filename is now derived from the URL path only (query string stripped), so img.jpg?v=2 lands as img.jpg. The full URL (including query string) still keys the cache, so distinct URLs remain distinct attachments.
  • Latent bug fixes in upload_image_from_url():
    • intermediate_image_sizes_advanced filter is now reliably removed - the previous code added and "removed" two separate closures, so remove_filter() never matched and the filter leaked into later media operations in the same request. Replaced with the stable __return_empty_array callable, detached in finally so it leaves on every exit path (success, error, exception).
    • Removed the redundant per-call http_request_timeout closure - it stacked one new closure per row (never removed) and was already covered by download_url($url, 30).
  • Whitespace around image URLs is now trimmed at the upload entry point, matching what the validator already accepted. Two rows differing only by leading/trailing whitespace now collapse to one attachment instead of two.
  • No new translatable strings, no schema changes, no admin UI changes. The fix is entirely server-side in the product importer.

Version 1.6.0

  • Category Manipulations page restructured into tabs
    • Each of the 6 operations plus Important Notes is now a separate tab
    • A tab's HTML and its (expensive) data are fetched on demand via a separate AJAX request the first time the tab is opened
    • Fixes the page-load timeout on stores with many product categories or media files - the shell page no longer runs every category/media calculation up front
    • The active tab is preserved in the URL hash, so a refresh (and the automatic reload after move/delete/clear operations) returns to the same tab
  • New AJAX handler: studiou_wcpcm_load_tab renders a manipulations tab partial on demand
  • Category and media-category count queries are now transient-cached (5 minutes, automatically invalidated when categories or product/category relationships change)
  • 7 new view partials under views/manipulations/
  • Cache busting - admin CSS/JS are now served under version-stamped filenames (admin-X.Y.Z.js / admin-X.Y.Z.css), so a version bump forces browsers to fetch fresh assets even on hosts that strip the ?ver= query string. No more manual hard refresh needed after an update.

Version 1.5.3

  • NEW: Update product variant prices - bulk-update regular price of product variations
    • Filter by selected product categories (with Check All / Uncheck All)
    • Variant attribute combobox (heads), populated from variation-eligible attributes
    • Variant value combobox, dynamically scoped to the chosen attribute and selected categories
    • New Price textbox with numeric validation
    • Dry Run button shows affected count + sample preview, no DB writes
    • Apply button commits via WooCommerce API (set_regular_price + WC_Product_Variable::sync)
    • Live affected-count label updates on every filter change
  • 4 new AJAX handlers: studiou_wcpcm_upvp_get_attributes, studiou_wcpcm_upvp_get_attribute_values, studiou_wcpcm_upvp_count, studiou_wcpcm_upvp_apply
  • Operation never touches order items, cart sessions, or historical order data
  • Added 23 new translation strings (English/Czech)

Version 1.5.2

  • NEW: Remove Not Assigned Media - permanently delete all unused uncategorized media files
    • Button with count of unused uncategorized media
    • Detects media not in any category, not used as featured image, not in product galleries, not attached to any post
    • Confirmation dialog before deletion
    • Real-time progress bar with batch processing (10 files at a time)
    • Comprehensive deletion statistics and error reporting
  • Fix: Media deletion now properly deletes physical files and attachment posts
    • After wp_delete_attachment(), verifies post was actually deleted via direct DB check
    • If post still exists, forces manual cleanup (term relationships, postmeta, post row)
    • Explicitly deletes physical files (main file + thumbnails) from disk
  • 2 new AJAX handlers: studiou_wcpcm_remove_unassigned_media, studiou_wcpcm_remove_unassigned_media_batch

Version 1.5.1

  • Fix: Clear Media Categories JS event handler not binding due to browser-cached old JS
  • Fix: Auto-detect any custom taxonomy registered for attachments (no longer limited to 3 hardcoded names)
  • Fix: Use spread operator for $wpdb->prepare() args for WP 6.8+ compatibility
  • Fix: Add return after wp_send_json_error() calls to prevent execution leak
  • Fix: Force wp_update_term_count_now() after batch deletion to refresh category counts
  • Improved JS initialization: each form init wrapped in try-catch (safeInit) so one error cannot block others
  • Always-on error logging for media operations (prefix: STUDIOU WC MEDIA:)
  • Added onsubmit="return false;" fallback on clear media form

Version 1.5.0

  • NEW: Clear Media Categories - permanently delete all media files from selected media categories
    • Checkbox list of media categories with file count per category
    • Check All / Uncheck All functionality
    • Confirmation dialog before deletion
    • Real-time progress bar for deletion operations
    • Batch processing for large-scale deletions (processes 10 media files at a time)
    • Comprehensive deletion statistics and error reporting
    • Enhanced warning messages for destructive operations
    • Auto-detection of media category taxonomy for attachments
    • Graceful fallback message when no media category plugin is installed
  • 2 new AJAX handlers: studiou_wcpcm_clear_media, studiou_wcpcm_clear_media_batch
  • Updated Category Manipulations page with new Clear Media Categories section
  • Added Important Notes entry for the new feature

Version 1.4.0

  • NEW: Product Import - Batch import variable products and variations from CSV
    • Batch processing - Processes 5 products per batch to avoid PHP timeout (60 sec limit)
    • Auto-create categories - Missing categories automatically created during import
    • Support for variable products with attributes
    • Support for product variations with parent references
    • Image URL handling with 30-second timeout, intermediate sizes disabled
    • Min/Max quantity support
    • 7 comprehensive import rules with validation
    • Failed products download for retry
    • Real-time progress bar showing "Processing: X / Y products"
    • Comprehensive error logging (always enabled, prefix: "STUDIOU WC IMPORT:")
    • Logs only skipped/failed items (not successful ones)
  • NEW: Product Export - Export products by category selection
    • Export variable products and their variations
    • Full category paths exported for subcategories (format: "Parent > Child")
    • Category hierarchy selection with product counts
    • Select All/Deselect All functionality
    • Full product data export (18 columns)
  • Technical improvements:
    • Two-phase import: Parse CSV to transient, then batch process
    • Smart category matching: exact name, slug, case-insensitive
    • Simple category lookup only (categories have unique names)
    • Image validation only checks format, not HTTP accessibility (prevents timeouts)
  • Added 3 new database/import/export classes for product management
  • Added 2 new view templates for product import/export
  • Enhanced JavaScript with recursive batch processing handlers
  • Added 71 new translation strings (English/Czech)
  • Updated plugin description to reflect product management capabilities
  • All operations use WooCommerce API (no direct SQL)

Version 1.3.0

  • New feature: Delete products in category - permanently delete all products and variants from selected categories
  • Real-time progress bar for deletion operations
  • Batch processing for large-scale deletions (processes 10 products at a time)
  • Automatic handling of variable products and their variations
  • Comprehensive deletion statistics and error reporting
  • Enhanced warning messages for destructive operations
  • Improved user interface with confirmation dialogs

Version 1.2.0

  • Added Category Manipulations functionality
  • New feature: Move products between categories
  • New feature: Batch description between categories
  • Enhanced admin interface with better user feedback
  • Improved security with proper nonce validation
  • Added comprehensive documentation
  • Direct database queries for reliable product detection

Version 1.1.0

  • Initial release with import/export functionality
  • Support for WooCommerce Protected Categories
  • CSV-based batch operations