# Why duplicate media files (`image-1.jpg`, `image-2.jpg`, …) appear on import The cause is in `includes/class-studiou-wc-product-manage-product-import.php`, not in the view. ## Where the upload happens - **Variable product row** → `process_variable_product()` calls `upload_image_from_url()` at line 287-292. - **Each variation row** → `process_variation()` calls `upload_image_from_url()` again at line 411-416. Every CSV row that has a non-empty `Obrázky` triggers an independent call. ## What `upload_image_from_url()` does (line 464-511) 1. `download_url($url, 30)` — downloads the remote file to a fresh temp file (PHP's `tmpfile()` name, not the basename of your URL). 2. Builds `$file_array['name'] = basename($url)`. 3. Calls `media_handle_sideload($file_array, 0)` — and there is **no check** for whether the same source URL is already in the Media Library. ## Why the `-1`, `-2`, `-3` suffix gets added `media_handle_sideload()` → `wp_handle_sideload()` → `wp_unique_filename()`. WordPress sees that `uploads/YYYY/MM/image.jpg` already exists from a previous row's import, so it renames the new upload to `image-1.jpg`, then `image-2.jpg`, etc. Each gets its own attachment post + physical file on disk. ## So with a typical variable product CSV One variable parent + N variations, all pointing at the same `image.jpg`: - Row 1 (variable) → uploads `image.jpg` (attachment #1) - Row 2 (variation) → re-downloads → `image-1.jpg` (attachment #2) - Row 3 (variation) → re-downloads → `image-2.jpg` (attachment #3) - …and so on. That's the exact `-.jpg` pattern observed. ## Contributing factors - **No URL-based dedup cache** anywhere in the importer. There's no lookup like "does an attachment already exist whose `guid` / `_source_url` / `_wp_attached_file` matches this remote URL?" - **No in-run dedup** either — even within a single batch, two rows with the same URL each trigger a fresh `download_url()` + `media_handle_sideload()`. - **`basename($url)`** is used as the local filename, so the collision detection only catches exact same-filename uploads in the same month folder. A URL like `…/img.jpg?v=2` still produces `img.jpg`, so collisions are likely. - The batch architecture (5 rows per AJAX request) doesn't share any cache between batches either — even an in-memory `array($url => $attachment_id)` would die when the request ends. ## Side effect worth noting Because each variation gets its *own* uploaded image, `$variation->set_image_id($image_id)` at line 414 points each variation at a different attachment ID — even though all the variations were supposed to share the parent's image. So this isn't just file clutter; the parent and every variation are individually referencing distinct copies of what is logically the same image. ## Fix shape (not applied — diagnosis only) A cache `array` keyed by source URL, checked **before** `download_url()`, that: 1. First queries existing attachments by `guid` / a custom `_source_url` meta / matching `_wp_attached_file` basename, and 2. If not found, performs the sideload and stores the resulting ID under the URL key (persisting the source URL in postmeta so future imports across requests hit the same attachment). That would collapse N+1 duplicate uploads per shared URL down to one.