CSV Resumable Importer for Tainacan
This add-on registers an extra CSV importer in Tainacan 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:
- Queues the item's attachment paths/URLs (stored in a transient serialized together with the process state).
- 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_timestill fails (pathological case). - Progress is still persisted at the core's ~20s
handle()checkpoint, not per iteration (forcing a per-iteration checkpoint would require changingBackground_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.
