About this plugin
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
g. 150 images in special_attachments ) fails with:
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_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.