# 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.1 ## 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 1. **Translations**: All new user-facing strings must use `__()` or `_e()` with text domain `'studiou-wc-product-cat-manage'` 2. **Security**: Always validate and sanitize user input, use nonces for form submissions 3. **WooCommerce Integration**: Use WooCommerce taxonomy 'product_cat' for all category operations 4. **Error Handling**: Provide clear error messages and validation feedback 5. **Compatibility**: Maintain HPOS (High-Performance Order Storage) compatibility declaration 6. **Direct Exits**: Always include `if (!defined('WPINC')) { die; }` at top of PHP files 7. **Batch Processing**: For operations on large datasets, use batch processing (10 items per batch recommended) 8. **Destructive Operations**: Always include confirmation dialogs and warning messages for operations that cannot be undone 9. **Progress Tracking**: For long-running operations, implement real-time progress bars ### Plugin Constants ```php 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): 1. `studiou-wc-product-cat-manage.php` — the `Version:` plugin header **and** the `STUDIOU_WCPCM_VERSION` constant 2. `CLAUDE.md` — the **Current Version** line at the top 3. `readme.md` — the `**Version: X.Y.Z**` line and a new `### Version X.Y.Z` changelog entry 4. `assets/js/admin.js` — the `console.log('STUDIOU WC: Admin script loaded vX.Y.Z')` banner 5. `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 `.gitignore`d 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: 1. WooCommerce API usage (no direct SQL) 2. Create vs. Update based on ID 3. Type validation (only variable/variation) 4. SKU uniqueness 5. Image URL validation 6. Parent reference validation 7. 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 1. **studiou_wcpcm_import** - Handles category CSV import 2. **studiou_wcpcm_export** - Generates category CSV export 3. **studiou_wcpcm_move_products** - Moves products between categories 4. **studiou_wcpcm_batch_description** - Updates descriptions for multiple categories 5. **studiou_wcpcm_delete_products** - Initial request to get product IDs for deletion 6. **studiou_wcpcm_delete_products_batch** - Processes product deletion in batches 7. **studiou_wcpcm_clear_media** - Initial request to get media IDs for deletion (NEW in v1.5) 8. **studiou_wcpcm_clear_media_batch** - Processes media deletion in batches (NEW in v1.5) 9. **studiou_wcpcm_remove_unassigned_media** - Gets IDs of unused uncategorized media (NEW in v1.5.2) 10. **studiou_wcpcm_remove_unassigned_media_batch** - Processes unassigned media deletion in batches (NEW in v1.5.2) 11. **studiou_wcpcm_upvp_get_attributes** - Lists variation attribute heads (NEW in v1.5.3) 12. **studiou_wcpcm_upvp_get_attribute_values** - Lists values for the selected attribute, scoped to selected categories (NEW in v1.5.3) 13. **studiou_wcpcm_upvp_count** - Counts and samples variations matching the current filter (NEW in v1.5.3) 14. **studiou_wcpcm_upvp_apply** - Commits new regular price to matching variations via WC API (NEW in v1.5.3) 15. **studiou_wcpcm_load_tab** - Renders a Category Manipulations tab partial on demand (NEW in v1.6.0) ### Product Operations (NEW in v1.4) 16. **studiou_wcpcm_product_import_parse** - Parses CSV file and stores in transient (Step 1) 17. **studiou_wcpcm_product_import_batch** - Processes batch of 5 products (Step 2, called recursively) 18. **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: 1. **Rule 1**: All operations performed via WooCommerce API (not direct SQL) 2. **Rule 2**: If ID = 0, item will be created; otherwise updated 3. **Rule 3**: Only "variable" or "variation" types are allowed 4. **Rule 4**: SKU (Katalogové číslo) must be unique in WooCommerce database 5. **Rule 5**: Image URL must be valid format (actual accessibility checked during download) 6. **Rule 6**: Parent reference (Nadřazené) must point to an existing variable product SKU 7. **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): 1. **Parse Phase**: CSV file is read entirely and stored in WordPress transient (expires in 1 hour) 2. **Batch Phase**: Products are processed in batches of 5 via recursive AJAX calls 3. **Progress Tracking**: Real-time progress bar shows "Processing: X / Y products" 4. **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