=== CSV Resumable Importer for Tainacan ===
Contributors: bauhaustech, marvila
Tags: tainacan, csv, importer, attachments, background-process
Requires at least: 5.9
Tested up to: 7.0
Requires PHP: 7.4
Stable tag: 1.0.0
License: GPL-3.0-or-later
License URI: https://www.gnu.org/licenses/gpl-3.0.html

Resumable CSV importer for Tainacan: imports attachments one at a time to avoid execution timeouts and duplicate items on large imports.

== Description ==

This add-on registers an extra CSV importer in [Tainacan](https://tainacan.org/) whose attachment processing is **resumable**: the files listed in the `special_attachments` column are imported **one per background iteration**, instead of all at once.

It does **not** modify Tainacan core — it registers an additional importer through the `tainacan-register-importers` hook, so it keeps working across Tainacan updates.

This is an independent add-on developed by Bauhaus Tech. It is **not affiliated with, endorsed by, or part of** the Tainacan project.

= The problem it solves =

A CSV import in which a single item has many attachments (e.g. 150 images in `special_attachments`) fails with:

`PHP Fatal error: Maximum execution time of 360 seconds exceeded in .../class-wp-image-editor-imagick.php`

…and then **restarts from the beginning, duplicating items**.

The stock Tainacan CSV importer imports **all** of an item's attachments inside a single `after_inserted_item()` call. Each file triggers `wp_generate_attachment_metadata()`, which generates thumbnails through Imagick — an expensive operation. The background process only checks its soft time limit (~20s) **between** `task()` iterations; since the 150 attachments run inside a single iteration, that limit is never checked mid-loop. The item alone exceeds PHP's hard `max_execution_time`, the process dies mid-task **without persisting progress**, and the cron healthcheck **re-dispatches the batch from the last checkpoint** — recreating already-imported items.

= How it works =

Instead of importing attachments inline, this importer:

1. **Queues** the item's attachment paths/URLs (stored in a transient serialized together with the process state).
2. Processes **one attachment per iteration**, staying on the current item until the queue is empty.

Because each attachment becomes its own iteration, the soft 20s limit applies **between files**: the batch checkpoints regularly and the import becomes resumable. Idempotency is reinforced by persisting the already-created item id, so a resume continues the attachments instead of recreating the item.

= Known limitations =

Because this plugin **cannot modify Tainacan core**:

* A single file whose processing alone exceeds `max_execution_time` still fails (pathological case).
* Progress is still persisted at the core's ~20s `handle()` checkpoint, not per iteration (forcing a per-iteration checkpoint would require changing `Background_Importer::task()` in core). A fatal **within the same 20s window** may reprocess what was done since the last checkpoint. The definitive fix is the equivalent change upstream in Tainacan.

== Installation ==

1. Upload the `csv-resumable-importer-for-tainacan` folder to `/wp-content/plugins/`, or install the ZIP via **Plugins → Add New → Upload Plugin**.
2. Activate **CSV Resumable Importer for Tainacan** in **Plugins**.
3. Requires the **Tainacan** plugin to be installed and active.
4. In **Tainacan → Importers**, choose **"CSV (resumable attachments)"** instead of the default CSV importer.

== Frequently Asked Questions ==

= Does it modify Tainacan core? =

No. It registers an additional importer through Tainacan's `tainacan-register-importers` hook and subclasses the core CSV importer. Tainacan updates do not overwrite it.

= Are the import options different from the native CSV importer? =

No. Delimiter, mapping, `server_path` and the special columns (`special_document`, `special_thumbnail`, `special_attachments[|APPEND|REPLACE]`) work exactly as in the native importer. Only the way attachments are processed changes.

= Is this an official Tainacan plugin? =

No. It is an independent add-on by Bauhaus Tech, not affiliated with the Tainacan project.

= Does it fix every possible timeout? =

It removes the real-world cause (a single item importing many attachments in one uninterruptible call). See "Known limitations" for the residual edge cases that would require a core change.

== Changelog ==

= 1.0.0 =
* Initial release. Resumable CSV importer that processes `special_attachments` one per background iteration.

== Upgrade Notice ==

= 1.0.0 =
Initial release.
