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
- Download the plugin ZIP file
- Go to WordPress Dashboard > Plugins > Add New
- Click "Upload Plugin" and select the ZIP file
- Click "Install Now"
- 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
- Go to Products > Export Product Categories
- Click "Export Product Categories"
- Download the generated CSV file
Importing Product Categories
- Go to Products > Import Product Categories
- Select your CSV file
- Click "Import Product Categories"
- Review the import results
Exporting Products (NEW in v1.4)
- Go to Products > Product Export
- Select categories using checkboxes
- Use "Select All" to select all categories
- Use "Deselect All" to deselect all categories
- Click "Export Selected Products"
- Download the generated CSV file
Importing Products (NEW in v1.4)
- Go to Products > Product Import
- Select your CSV file (UTF-8 encoding)
- Click "Process Import File"
- 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"
- Review the import results showing:
- Successful imports
- Failed imports
- Skipped items
- Detailed messages for skipped/failed items only
- 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
- Go to Products > Category Manipulations
- Select the source category (from which products will be moved)
- Select the target category (to which products will be moved)
- Click "Do" to execute the move operation
- 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
- Go to Products > Category Manipulations
- Scroll to the "Batch description between categories" section
- Select one or more categories using the checkboxes
- Use "Check All" to select all categories
- Use "Uncheck All" to deselect all categories
- Enter the description text in the textarea
- Click "Do" to apply the description to all selected categories
- 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
- Go to Products > Category Manipulations
- Scroll to the "Delete products in category" section
- Select one or more categories using the checkboxes
- Use "Check All" to select all categories
- Use "Uncheck All" to deselect all categories
- Click "Delete" button (you will be asked to confirm)
- Watch the progress bar as products are being deleted in batches
- 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)
- Go to Products > Category Manipulations
- Scroll to the "Clear Media Categories" section
- 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
- Click "Delete" button (you will be asked to confirm)
- Watch the progress bar as media files are being deleted in batches
- 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)
- Go to Products > Category Manipulations
- Scroll to the "Remove Not Assigned Media" section
- The button shows the count of unused uncategorized media files
- Click "Delete unused uncategorized media (N)" button (you will be asked to confirm)
- Watch the progress bar as media files are being deleted in batches
- 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)
- Go to Products > Category Manipulations
- Scroll to the "Update product variant prices" section
- Select one or more product categories using the checkboxes
- Use "Check All" to select all categories
- Use "Uncheck All" to deselect all categories
- Pick a Variant attribute from the dropdown (heads such as Color, Size — populated from variation-eligible attributes in the store)
- Pick a Variant attribute value from the dropdown (values are scoped to the chosen attribute and selected categories)
- Enter the New Price
- Watch the Affected variations label — it updates live as you change filters
- Click Dry Run to preview the count and a sample of variations that would be updated (no DB writes)
- Click Apply to commit the new regular price; you will be asked to confirm
- 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