Skip to content

Everything for WordPress, web development — and beyond

🔧 WP All Import: how to collect all post images into a single gallery

🔧 WP All Import: how to collect all post images into a single gallery

Imported a hundred posts through WP All Import, and the images scattered across the content randomly: stretched to full width in some places, squeezed against text in others, and hanging as broken links elsewhere. Going through each post manually is an evening wasted.

There is a way to collect everything into a single gallery. Automatically, without manual content editing. The method works for both fresh imports and posts uploaded a month ago. Below are two approaches: the easy one (on the fly, via the pmxi_gallery_image hook) and post-factum (with bulk update). Both tested on WP All Import 4.9+.

💡 Quick overview:

  • Prepare CSV or XML: image links as full URLs, one per line
  • In the import template, configure the Images section and specify the field with images
  • Add the pmxi_gallery_image hook to functions.php, the gallery assembles itself during import
  • For old posts: a function to replace <img> with the gallery shortcode and bulk update

How to prepare images for import

Before running the import, image links must be in the correct format. WP All Import downloads images only if the URL is full, direct, and points to a file, not an HTML page.

Suppose on the old site the gallery looks like this:

1<a href="/cache/images/photo1.jpg" data-lightbox="group:1" title="Photo 1">
2 <img src="/cache/images/photo1_thumb.jpg" alt="Photo 1">
3</a>
4<a href="/cache/images/photo2.jpg" data-lightbox="group:1" title="Photo 2">
5 <img src="/cache/images/photo2_thumb.jpg" alt="Photo 2">
6</a>

After parsing, in the CSV file for import, the links must become full URLs, one per line, without HTML wrapper:

1http://newsite.com/files/photo1.jpg
2http://newsite.com/files/photo2.jpg

Where http://newsite.com is the domain of the site you're importing to. Critical: if the links are relative or point to the old domain, WP All Import will not pick up the files and will not upload them to the media library.

The links in the post body must match one-to-one with those you're feeding to the plugin for upload. Otherwise, after import, some <img> tags will remain with old URLs and will not be included in the gallery.

Configuring the import template in WP All Import

In the plugin interface, go to the import template. The main section here is Images. It looks like this:

WP All Import image settings interface

In the Images section, specify the field that contains image links. Usually this is a separate CSV cell (for example, gallery_images), where links are listed with a separator, by default |:

1http://newsite.com/files/photo1.jpg | http://newsite.com/files/photo2.jpg | http://newsite.com/files/photo3.jpg

WP All Import will parse the string, download each image, and add it to the WordPress media library. But the images are just attached to the post as attachments for now. We'll assemble the gallery separately.

Be sure to check how the plugin handles the upload. Click Preview & Test, then Run Test. A green check next to the number of images means everything is configured correctly. A red cross means check the URLs: they must be full and direct.

Before starting the import, upload the image files to the files folder in the site root, if the plugin takes images from the server and not from external URLs.

The cleanest way is to assemble the gallery right during import. WP All Import provides the pmxi_gallery_image hook, which fires for each uploaded image. You intercept the attachment ID and save it in the post meta field in the desired format.

Three tested variants, choose for your theme or gallery plugin.

Variant 1: array of attachment IDs. Suitable for most themes expecting the gallery as an array of attachment IDs:

1function my_gallery_ids($post_id, $att_id, $filepath, $is_keep_existing_images)
2{
3 $key = '_my_gallery';
4 $gallery = get_post_meta($post_id, $key, true);
5
6 if (empty($gallery)) {
7 $gallery = array();
8 }
9
10 if (!in_array($att_id, $gallery)) {
11 $gallery[] = $att_id;
12 update_post_meta($post_id, $key, $gallery);
13 }
14}
15add_action('pmxi_gallery_image', 'my_gallery_ids', 10, 4);

Variant 2: array of URLs. If the theme needs direct links to full-size images:

1function my_gallery_urls($post_id, $att_id, $filepath, $is_keep_existing_images)
2{
3 $key = '_my_gallery';
4 $size = 'full';
5 $gallery = get_post_meta($post_id, $key, true);
6
7 if (empty($gallery)) {
8 $gallery = array();
9 }
10
11 if (!isset($gallery[$att_id])) {
12 $src = wp_get_attachment_image_src($att_id, $size);
13 $gallery[$att_id] = $src[0];
14 update_post_meta($post_id, $key, $gallery);
15 }
16}
17add_action('pmxi_gallery_image', 'my_gallery_urls', 10, 4);

Variant 3: string with separator. If the meta field stores IDs separated by comma (format "23,25,31"):

1function my_gallery_string($post_id, $att_id, $filepath, $is_keep_existing_images)
2{
3 $key = '_my_gallery';
4 $sep = ',';
5 $gallery = get_post_meta($post_id, $key, true);
6
7 if (is_string($gallery) || empty($gallery) || $gallery == false) {
8 $gallery = explode($sep, $gallery);
9 if (!in_array($att_id, $gallery)) {
10 if ($gallery[0] == '') unset($gallery[0]);
11 $gallery[] = $att_id;
12 update_post_meta($post_id, $key, implode($sep, $gallery));
13 }
14 }
15}
16add_action('pmxi_gallery_image', 'my_gallery_string', 10, 4);

The code is inserted into the theme's functions.php. After the import is complete, the hook can be removed, the meta field is already populated. Advantage of this method: the gallery is ready immediately after import, without additional passes.

What to do with already imported posts

If posts are already uploaded and images hang in the content as regular <img> tags, you need a different approach. Go through all posts and replace the tags with the gallery shortcode.

The function below collects all attachment IDs of a post and replaces <img> in the content with [gallery ids="..."]:

1function replace_post_images_with_gallery($post_id)
2{
3 $post = get_post($post_id);
4 if (!$post) return;
5
6 $attachments = get_attached_media('image', $post_id);
7
8 if (empty($attachments)) return;
9
10 $ids = array();
11 foreach ($attachments as $att) {
12 $ids[] = $att->ID;
13 }
14
15 $gallery_shortcode = '[gallery ids="' . implode(',', $ids) . '"]';
16 $content = preg_replace('/<img[^>]+>/i', '', $post->post_content);
17 $content = $gallery_shortcode . "\n\n" . $content;
18
19 wp_update_post(array(
20 'ID' => $post_id,
21 'post_content' => $content,
22 ));
23}

Then run a bulk update:

  • In the admin panel, go to the list of all posts.
  • In screen options, set the number of items to 50 (optimal so the server doesn't crash).
  • Select all posts, choose "Update" in bulk actions, and apply.

WordPress will go through each post, call save_post and related hooks. If the function in functions.php is tied to save_post, it will execute. After completion, **remove the code from **functions.php, otherwise, with each post save, the content will be rebuilt again.

⁉️🤔 Frequently asked questions

WP All Import** is not downloading images during import, what's wrong?**

Links in the import file must be full URLs (with http:// or https://) and lead directly to an image file, not to an HTML page. Check write permissions for wp-content/uploads: if the server cannot save the file, the image import is silently skipped. The most common reason is a mismatch between links in the content body and in the Images field of the template. If the content has http://oldsite.com/img.jpg, and Images is fed http://newsite.com/files/img.jpg, the plugin will not link them and the image will remain broken. URLs must match one-to-one.

Why is pmxi_gallery_image better than post-import?

The hook fires for each image at the moment of upload, the gallery is ready right after import, without a second pass. Post-import via wp_update_post loads the server: a thousand posts give a thousand save_post calls. For volumes up to 100 posts, the difference is negligible, but for large migrations, the hook saves hours. Plus, pmxi_gallery_image gives access to the path of the uploaded file and attachment ID, you can immediately prescribe any logic: distribute by folders, add to slider, sync with CDN. Post-import does not provide such flexibility.

Is it necessary to remove the code from functions.php after import?

Yes. If the function hangs on pmxi_gallery_image, it fires on ANY attachment addition, the result: duplicates in the gallery meta field when manually uploading images. The hook executes once, after the import is complete, it can be safely removed. If the function is tied to save_post or used in bulk update, even more so remove it. Otherwise, each post edit will rebuild the content, removing <img> tags and rewriting the gallery.

How to leave individual images outside the gallery?

Exclude them from replacement. In the variant with pmxi_gallery_image, add a condition by size or alt text. In the variant with post-import, instead of preg_replace for all <img>, use selective replacement: leave images with a specific CSS class or attribute, remove the rest and replace with gallery. For example, <img class="keep"> remains in the content, all other <img> are replaced with [gallery]. Solved by refining the regex in the replacement function.

Is WP All Import Pro necessary or is the free version enough?

The free version can import images to the media library and attach them to a post. The pmxi_gallery_image hook is available in it as well. The Pro version adds: loading images from external URLs, Cron imports on schedule, executing PHP functions directly in the import template, and support for custom fields. For a one-time import with local files, the free version is more than enough. Pro is needed when images are on a third-party server and you don't want to download them manually, as well as for ACF fields, WooCommerce import, and working with custom post types.

Which method to choose for your task

If you are just planning an import, assemble the gallery on the fly via pmxi_gallery_image. Faster, cleaner, and without double load on the server. Any of the three variants above works: the choice depends on what format your theme or plugin expects the gallery in.

If posts are already uploaded and images are scattered across the content, take the function to replace <img> with [gallery] and run a bulk update. For small volumes (up to 200 posts), this will take a couple of minutes. For thousands of posts, it's wiser to split into batches of 50.

WP All Import itself is one of the most flexible importers for WordPress. 200,000+ active installations, the free version on WordPress.org covers most migration tasks. And the Pro version removes the last limitations on external URLs and Cron imports. Try it.