CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
QDR - Studiou WC Export/Import Product Categories is a WordPress plugin that extends WooCommerce to provide batch export/import functionality for both product categories and products, along with category manipulation tools.
Current Version: 1.7.2
Requirements
- WordPress 6.8.1+
- PHP 8.2+
- WooCommerce 9.8+
- WooCommerce Protected Categories 2.7+ (optional, for visibility features)
Plugin Architecture
Core Files
- studiou-wc-product-cat-manage.php - Main plugin file containing:
- Plugin initialization and dependency loading
- Admin menu registration under Products menu
- Asset enqueueing for admin pages — CSS/JS are served under version-stamped filenames (
admin-X.Y.Z.js / admin-X.Y.Z.css, auto-generated from the source files) so cache busting works on hosts that strip the ?ver= query string. Versioned copies are gitignored.
- WooCommerce HPOS compatibility declaration
- Text domain loading for translations
Class Structure (includes/)
The plugin follows a modular class-based architecture:
class-studiou-wc-product-cat-manage-db.php - Database operations layer
- Handles all database queries for product categories
- Manages category hierarchy (parent/child relationships)
- Provides category formatting and data retrieval
- Interfaces with WooCommerce taxonomy and WooCommerce Protected Categories plugin
class-studiou-wc-product-cat-manage-export.php - Export functionality
- Generates CSV files from product categories
- Includes all category properties (name, slug, parent, description, display-type, visibility, protected-passwords)
- Handles UTF-8 encoding and proper CSV formatting
class-studiou-wc-product-cat-manage-import.php - Import functionality
- Processes CSV files with operations: 'A' (add), 'U' (update), 'D' (delete)
- Validates data and handles errors
- Creates/updates/deletes categories based on operation column
- Manages WooCommerce Protected Categories settings
class-studiou-wc-product-cat-manage-manipulator.php - Category manipulation operations
- Move products between categories (removes from source, adds to target)
- Batch description updates for multiple categories
- Delete products in category (permanently deletes products and variants)
- Clear Media Categories (permanently deletes media files from media categories) (NEW in v1.5)
- Remove Not Assigned Media (deletes unused uncategorized media) (NEW in v1.5.2)
- Update product variant prices (regular_price only, by category + attribute filter) (NEW in v1.5.3)
- Uses direct database queries for reliable product detection
get_categories_with_counts() / get_media_categories_with_counts() are transient-cached (5 min, busted on term changes) — uncached bodies live in the *_uncached() variants (NEW in v1.6.0)
handle_load_tab_ajax() renders a manipulations tab partial on demand (NEW in v1.6.0)
- Batch processing for delete operations (10 items per batch)
- Auto-detects media category taxonomy (any custom taxonomy registered for attachments)
- Robust media deletion with post-deletion verification and manual fallback cleanup
- Always-on error logging for media operations (prefix: "STUDIOU WC MEDIA:")
class-studiou-wc-product-manage-product-db.php - Product database operations (NEW in v1.4)
- Retrieves product categories with hierarchy
- Gets products by category IDs
- Validates product SKU uniqueness
- Validates image URLs
- Manages product attributes (create if not exists)
class-studiou-wc-product-manage-product-import.php - Product import functionality (NEW in v1.4)
- Batch processing - Processes 5 products per batch to avoid PHP timeout (60 second limit)
- Parses CSV and stores in WordPress transient for batch processing
- Creates/updates variable products via WooCommerce API
- Creates/updates product variations via WooCommerce API
- Enforces 7 comprehensive import rules
- Auto-creates missing categories - Creates categories if they don't exist
- Handles product attributes, images, categories
- Image download with 30-second timeout, intermediate sizes disabled
- Generates failed products CSV for retry
- Supports Min/Max quantity metadata
- Comprehensive error logging (always enabled, prefix: "STUDIOU WC IMPORT:")
- Logs only skipped/failed items (not successful ones)
- Source-URL deduplication (NEW in v1.6.1): each unique
Obrázky URL is downloaded once and reused via a _studiou_wcpcm_source_url attachment postmeta plus a per-request static cache, so all rows sharing an image (variable parent + variations) point at one attachment
class-studiou-wc-product-manage-product-export.php - Product export functionality (NEW in v1.4)
- Exports products by category selection
- Includes variable products and variations
- Generates CSV with 18 columns of product data
- Exports full category paths for subcategories (format: "Parent > Child")
- Handles product attributes, images, pricing
- Creates downloadable export files
Views (views/)
- import.php - Category import page UI
- export.php - Category export page UI
- manipulations.php - Category manipulations page shell (tab bar + empty content container). As of v1.6.0 it renders no heavy data; each tab is loaded on demand via the
studiou_wcpcm_load_tab AJAX handler.
- manipulations/ - Tab partials, one per operation (NEW in v1.6.0):
tab-move.php, tab-batch-description.php, tab-delete-products.php, tab-clear-media.php, tab-remove-unassigned.php, tab-upvp.php, tab-notes.php. Each partial fetches only its own data.
The page UI provides these operations:
- Move products between categories (two dropdowns + "Do" button)
- Batch description between categories (checkbox list + textarea + "Do" button)
- Delete products in category (checkbox list + "Delete" button + progress bar)
- Clear Media Categories (checkbox list + "Delete" button + progress bar) (NEW in v1.5)
- Remove Not Assigned Media ("Delete unused uncategorized media (N)" button + progress bar) (NEW in v1.5.2)
- Update product variant prices (checkbox list + 2 comboboxes + price input + Dry Run/Apply buttons + live affected-count label) (NEW in v1.5.3)
- product-import.php - Product import page UI (NEW in v1.4)
- File upload for CSV import
- Progress bar for import operations
- Import results with statistics
- Failed products download button
- Import rules documentation
- product-export.php - Product export page UI (NEW in v1.4)
- Category hierarchy selection with checkboxes
- Select All/Deselect All buttons
- Export results with download link
- Export information documentation
Assets
- assets/css/admin.css - Admin styling including:
- Progress bar styling
- Warning message styling (yellow background for destructive operations)
- Danger button styling (red for delete operations)
- assets/js/admin.js - Admin JavaScript including:
safeInit() wrapper - each form init is isolated in try-catch so one error cannot block others
- AJAX handlers for all category operations
- AJAX handlers for product import/export operations (NEW in v1.4)
- AJAX handlers for clear media categories operations (NEW in v1.5)
- AJAX handlers for remove unassigned media operations (NEW in v1.5.2)
- Batch processing logic for delete and media deletion operations
- Real-time progress bar updates
- Confirmation dialogs for destructive operations
- Failed products CSV download handler
- Select All/Deselect All handlers for category selection
Translations
- languages/ - Contains .pot, .po, and .mo files
- Text domain:
studiou-wc-product-cat-manage
- All user-facing strings must be wrapped in translation functions:
__(), _e(), sprintf()
CSV Formats
Product Category CSV Format
CSV files use comma separators, double-quote string isolation, UTF-8 encoding:
| Column |
Description |
| name |
Category name (required, used as identifier) |
| url-name |
URL slug |
| parent-name |
Parent category name (empty if root) |
| description |
Category description |
| display-type |
Values: 'default', 'products', 'subcategories', 'both' |
| visibility |
Values: 'public', 'protected' (WooCommerce Protected Categories) |
| protected-passwords |
Pipe-separated passwords (|) if visibility='protected' |
| operation |
'A' (add), 'U' (update), 'D' (delete) |
Product CSV Format (NEW in v1.4)
CSV files use comma separators, double-quote string isolation, UTF-8 encoding:
| 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) |
| Kategorie |
Categories (pipe-separated) |
| Obrázky |
Image URL (must be valid) |
| 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 |
Development Guidelines
When Modifying Code
- Translations: All new user-facing strings must use
__() or _e() with text domain 'studiou-wc-product-cat-manage'
- Security: Always validate and sanitize user input, use nonces for form submissions
- WooCommerce Integration: Use WooCommerce taxonomy 'product_cat' for all category operations
- Error Handling: Provide clear error messages and validation feedback
- Compatibility: Maintain HPOS (High-Performance Order Storage) compatibility declaration
- Direct Exits: Always include
if (!defined('WPINC')) { die; } at top of PHP files
- Batch Processing: For operations on large datasets, use batch processing (10 items per batch recommended)
- Destructive Operations: Always include confirmation dialogs and warning messages for operations that cannot be undone
- Progress Tracking: For long-running operations, implement real-time progress bars
Plugin Constants
STUDIOU_WCPCM_VERSION // Plugin version
STUDIOU_WCPCM_PLUGIN_DIR // Plugin directory path
STUDIOU_WCPCM_PLUGIN_URL // Plugin URL
STUDIOU_WCPCM_PLUGIN_BASENAME // Plugin basename
Release Process (version bump)
On every release, bump the version in all of these places (keep them identical):
studiou-wc-product-cat-manage.php — the Version: plugin header and the STUDIOU_WCPCM_VERSION constant
CLAUDE.md — the Current Version line at the top
readme.md — the **Version: X.Y.Z** line and a new ### Version X.Y.Z changelog entry
assets/js/admin.js — the console.log('STUDIOU WC: Admin script loaded vX.Y.Z') banner
languages/*.po — the Project-Id-Version header (optional but preferred)
Asset file renaming — automatic, do NOT do it by hand
Admin CSS/JS are served under version-stamped filenames (assets/js/admin-X.Y.Z.js, assets/css/admin-X.Y.Z.css) so cache busting works on hosts that strip the ?ver= query string (e.g. studiou.cz).
- The renaming is handled at runtime by
get_cache_busted_asset_url() in the main plugin file. It copies the source admin.js / admin.css to a versioned filename built from STUDIOU_WCPCM_VERSION, refreshes it whenever the source changes, and deletes stale copies.
- Always edit the source files
assets/js/admin.js and assets/css/admin.css — never the admin-X.Y.Z.* copies.
- The
admin-X.Y.Z.* copies are generated build artifacts: they are .gitignored and must not be committed.
- After bumping
STUDIOU_WCPCM_VERSION, the new versioned filenames are produced automatically on the next admin page load — no manual file renaming is required.
Translations
After changing any translatable string, update languages/studiou-wc-product-cat-manage.po and languages/studiou-wc-product-cat-manage-cs_CZ.po, then recompile languages/studiou-wc-product-cat-manage-cs_CZ.mo with msgfmt.
Admin Menu Structure
All pages are added under Products menu:
- Import Product Categories (slug:
studiou-import-product-categories)
- Export Product Categories (slug:
studiou-export-product-categories)
- Category Manipulations (slug:
studiou-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)
- Product Import (slug:
studiou-product-import) - NEW in v1.4
- Product Export (slug:
studiou-product-export) - NEW in v1.4
Key Integration Points
- WooCommerce Protected Categories: Plugin extends category visibility with 'public'/'protected' settings and password protection
- Product Assignment: When moving products, the plugin modifies product-category term relationships while preserving other category assignments
- Hierarchy Management: Categories maintain parent-child relationships via
parent-name field
- Product Deletion: Uses WooCommerce
wc_get_product() and product->delete(true) for proper product deletion
- Automatically handles variable products by deleting all variations first
- Force delete (true parameter) ensures permanent removal bypassing trash
- Processes in batches to prevent PHP timeouts and memory issues
- Product Import/Export (NEW in v1.4): All operations performed via WooCommerce API
- Uses
WC_Product_Variable and WC_Product_Variation classes
- Uses
WC_Product_Attribute for attribute management
- Image uploads via
media_handle_sideload()
- SKU validation via
wc_get_product_id_by_sku()
- Attribute taxonomy creation via
wc_create_attribute()
- 7 comprehensive import rules enforced
Security notes
- Image URLs in product imports are fetched server-side without a host allow-list (
upload_image_from_url() → download_url($url, 30)). An admin who can upload a CSV can cause the server to issue HTTP requests to any URL they put in the Obrázky column, including internal hostnames and cloud metadata endpoints. The risk is gated by the manage_woocommerce capability — on low-trust shops, restrict who has it. (L6 in review-00.)
- Failed-products retry is creation-only. The CSV produced by "Save Failed Products" carries
ID = 0 for every row. On re-import, the ID-based create-vs-update rule will try to create, and the SKU-uniqueness rule will then skip anything that has already been created. So the retry workflow can only finish the rows that never landed; rows that partially succeeded and need an update aren't fixable through the failed-CSV path. Edit the source CSV with a non-zero ID for those rows instead. (L8 in review-00.)
Testing Notes
Category Operations
- Test import/export with categories that have special characters, quotes, commas
- Test category hierarchy (parent/child relationships)
- Test moving products between categories when products have multiple category assignments
- Test batch description updates with multiline text
- Test delete products operation with:
- Simple products
- Variable products with multiple variations
- Products in multiple categories
- Large numbers of products (test batch processing)
- Edge cases: empty categories, categories with only variations
Product Import/Export Operations (NEW in v1.4)
- Test product import with:
- Variable products with multiple attributes
- Product variations with valid parent references
- Invalid SKUs (duplicate, empty)
- Invalid image URLs (404, malformed)
- Invalid parent references
- Missing required fields (price for variations)
- Special characters in product names and descriptions
- Large CSV files (test progress bar)
- Failed products download and re-import
- Test product export with:
- Multiple category selections
- Category hierarchy display
- Empty categories
- Categories with only variable products
- Categories with only variations
- Select All/Deselect All functionality
- Test all 7 import rules:
- WooCommerce API usage (no direct SQL)
- Create vs. Update based on ID
- Type validation (only variable/variation)
- SKU uniqueness
- Image URL validation
- Parent reference validation
- Variation price requirement
Clear Media Categories Operations (NEW in v1.5)
- Test with media category plugin installed (e.g., Media Library Categories)
- Test without media category plugin installed (should show graceful fallback message)
- Test deletion with:
- Single media category selected
- Multiple media categories selected
- Empty media categories
- Large numbers of media files (test batch processing)
- Check All/Uncheck All functionality
- Verify confirmation dialog appears before deletion
- Verify progress bar updates correctly during batch deletion
- Verify media files are actually removed from disk
- Verify deletion statistics are accurate
- Test with media files used as product images (verify WooCommerce product references are handled)
- Verify physical files are deleted from disk (check wp-content/uploads/)
- Verify attachment posts are removed from Media Library
Remove Not Assigned Media Operations (NEW in v1.5.2)
- Verify button count matches actual unused uncategorized media
- Test deletion with:
- Media not in any category and not used anywhere
- Media used as featured image (should NOT be deleted)
- Media used in WooCommerce product galleries (should NOT be deleted)
- Media attached to a post (post_parent > 0, should NOT be deleted)
- Media in a media category (should NOT be deleted)
- Large numbers of unused media (test batch processing)
- Verify confirmation dialog appears before deletion
- Verify progress bar updates correctly
- Verify physical files and attachment posts are both deleted
- Verify button count updates after page reload
Update Product Variant Prices Operations (NEW in v1.5.3)
- Test happy path with a global taxonomy attribute (e.g.
pa_color = red) — Dry Run shows correct count + sample, Apply commits new regular price
- Test happy path with a custom non-taxonomy attribute (product-level)
- Test multi-category selection — variations counted only once each
- Test no-match filter — Apply button stays disabled, label shows 0
- Test invalid price input (empty / negative / non-numeric) — server-side error, no DB write
- Verify a user without
manage_woocommerce cannot trigger AJAX
- Verify nonce tampering returns "Security check failed"
- Order data integrity: place a test order with a variation, run UPVP, verify the order line item retains the original price (only product-side price changes)
- Verify parent variable product price-range cache is refreshed (
WC_Product_Variable::sync + wc_delete_product_transients) — storefront price range reflects new price
- Verify Czech translations render when site locale is
cs_CZ
- Verify asset version query string updates from
1.5.2 to 1.5.3 (note: studiou.cz strips ?ver= — instruct user to hard-refresh)
General
- Verify translations are properly loaded (English/Czech)
- Verify progress bars update correctly
- Verify confirmation dialogs appear for destructive operations
- Test with WP_DEBUG enabled to catch errors
AJAX Handlers
The plugin registers the following AJAX actions:
Category Operations
- studiou_wcpcm_import - Handles category CSV import
- studiou_wcpcm_export - Generates category CSV export
- studiou_wcpcm_move_products - Moves products between categories
- studiou_wcpcm_batch_description - Updates descriptions for multiple categories
- studiou_wcpcm_delete_products - Initial request to get product IDs for deletion
- studiou_wcpcm_delete_products_batch - Processes product deletion in batches
- studiou_wcpcm_clear_media - Initial request to get media IDs for deletion (NEW in v1.5)
- studiou_wcpcm_clear_media_batch - Processes media deletion in batches (NEW in v1.5)
- studiou_wcpcm_remove_unassigned_media - Gets IDs of unused uncategorized media (NEW in v1.5.2)
- studiou_wcpcm_remove_unassigned_media_batch - Processes unassigned media deletion in batches (NEW in v1.5.2)
- studiou_wcpcm_upvp_get_attributes - Lists variation attribute heads (NEW in v1.5.3)
- studiou_wcpcm_upvp_get_attribute_values - Lists values for the selected attribute, scoped to selected categories (NEW in v1.5.3)
- studiou_wcpcm_upvp_count - Counts and samples variations matching the current filter (NEW in v1.5.3)
- studiou_wcpcm_upvp_apply - Commits new regular price to matching variations via WC API (NEW in v1.5.3)
- studiou_wcpcm_load_tab - Renders a Category Manipulations tab partial on demand (NEW in v1.6.0)
Product Operations (NEW in v1.4)
- studiou_wcpcm_product_import_parse - Parses CSV file and stores in transient (Step 1)
- studiou_wcpcm_product_import_batch - Processes batch of 5 products (Step 2, called recursively)
- studiou_wcpcm_product_export - Generates product CSV export by category selection
All AJAX handlers include:
- Nonce verification (
studiou-wcpcm-nonce)
- Permission checks (
manage_woocommerce capability)
- Output buffer cleaning to prevent JSON corruption
- Comprehensive error logging (always enabled for product import)
Product Import Rules (v1.4)
The product import functionality enforces 7 comprehensive 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 (actual 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)
Product Import Technical Details (v1.4)
Batch Processing Architecture
To avoid PHP timeout issues (typically 60 seconds on production servers):
- Parse Phase: CSV file is read entirely and stored in WordPress transient (expires in 1 hour)
- Batch Phase: Products are processed in batches of 5 via recursive AJAX calls
- Progress Tracking: Real-time progress bar shows "Processing: X / Y products"
- Result Accumulation: Success/failed/skipped counts are accumulated across batches
Category Handling
- Simple name lookup only - Categories have unique names throughout the system
- No hierarchy detection - Dashes and other characters are part of category names, not separators
- Auto-create: If category doesn't exist, it's automatically created during import
- Lookup methods: Tries exact name match, slug match, then case-insensitive search
Image Processing
- 30-second timeout per image download
- Intermediate sizes disabled during import for speed
- Graceful failure: Failed image downloads don't stop import, just logged
Error Logging
- Always enabled (no WP_DEBUG required)
- Prefix: "STUDIOU WC IMPORT:" for easy filtering
- Only logs failures: Success messages not logged to reduce noise
- Detailed debugging: Shows category lookup attempts, creation, and assignment
Items that fail validation are:
- Skipped during import
- Logged with SKIPPED or FAILED prefix
- Added to failed items list
- Available for download via "Save Failed Products" button
- Can be corrected and re-imported
- new Rule is that product category has unique name through whole product categories