WordPress Google Images Sitemap
Google Images XML sitemap for WordPress — automatically lists every image on your site so Google Images can find and index them
by Web Devs · github.com/webdevs-net/wp-google-images-sitemap · website
Install
No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:
wp plugin install https://github.com/webdevs-net/wp-google-images-sitemap/archive/refs/heads/main.zipReadme
WordPress Google Images Sitemap
Get your WordPress images found on Google Images.
WordPress builds an XML sitemap for your posts and pages automatically — but it leaves every image out entirely. That's a missed opportunity: Google Images sends real search traffic, and if your images aren't in a sitemap, Google may never find or index them.
This lightweight WordPress plugin fixes that. Activate it, and every image on your site gets listed in a proper Google Images XML sitemap that plugs straight into WordPress's existing sitemap — no configuration, nothing written to disk, nothing to babysit.
/wp-sitemap.xml ← your site's existing sitemap, now lists the line below
/wp-sitemap-images-1.xml ← this plugin
How it works
WordPress core has generated sitemaps since version 5.5, but it technically cannot emit an image sitemap: the piece of core that renders sitemap XML only writes flat, simple fields, and Google's image sitemap format needs a nested element core doesn't support. This plugin adds that missing piece. Your posts, pages, custom post types and taxonomies keep being indexed by core exactly as before — the image document just appears alongside them.
It was written to replace two abandoned image-sitemap plugins on a 2,900-image gallery site. Both had written static XML into the web root, and that XML was still being served years later — pointing at a CDN hostname that had been decommissioned two host migrations earlier. Nothing regenerated it and nothing noticed.
So the design constraints here are deliberate:
- Nothing is ever written to disk. Output is generated per request and cached in transients. There is no file to go stale, and no file to forget about.
- Same-origin images only. An attachment URL pointing at some other host is dropped unless you explicitly allow that host. Retired CDN domains linger in the media library long after they stop resolving.
<image:loc>and nothing else. Google deprecated<image:caption>,<image:title>,<image:geo_location>and<image:license>in May 2022 and ignores them. Omitting them keeps the document small and guarantees no author-supplied text is ever echoed into XML.
Requirements
- WordPress 5.5 or newer, with core sitemaps enabled
- PHP 7.2 or newer
Install
As a normal plugin:
cd wp-content/plugins
git clone https://github.com/webdevs-net/wp-google-images-sitemap.git
wp plugin activate wp-google-images-sitemap
Or as a must-use plugin, if you want it loaded unconditionally and not deactivatable from the admin:
cp image-sitemap.php wp-content/mu-plugins/zz-image-sitemap.php
Then confirm:
curl -s https://example.com/wp-sitemap.xml | grep images
curl -s https://example.com/wp-sitemap-images-1.xml | head -20
No rewrite rules are added, so there is nothing to flush. Core's existing
^wp-sitemap-([a-z]+?)-(\d+)\.xml$ rule already routes the URL.
Where it finds images
For every published post of every public post type, in order:
- Featured image
- Inline editor and block images — anything carrying core's
wp-image-<id>class - Galleries —
[gallery ids="…"]and thecore/galleryblock'sidsattribute - Attachment IDs in post meta, at any depth, stored under a conventional key
(
attach_id,image_id,attachment_id,thumb_id,thumbnail_id). Page builders serialize a whole layout into one meta value, so the tree is unserialized and walked.
Posts that are password protected, or flagged noindex by Yoast, Rank Math or The SEO
Framework, are skipped.
Filters
| Filter | Purpose |
|---|---|
image_sitemap_post_types |
Post types to scan. Defaults to public types minus attachment. |
image_sitemap_exclude_post |
Skip an individual post. |
image_sitemap_post_attachment_ids |
Add or remove attachment IDs for a post, before URLs are resolved. |
image_sitemap_id_meta_keys |
Meta key names that hold a single attachment ID. |
image_sitemap_allow_external_host |
Keep images on an off-site host (a CDN you actually still use). |
Adding a source the plugin cannot see
The common case: album pages that display galleries by taxonomy term rather than by attachment ID, so the visible tiles are other posts' featured images. That is site-specific, so it belongs in a filter rather than in the plugin:
add_filter( 'image_sitemap_post_attachment_ids', function ( $ids, $post_id ) {
// Your builder stores which gallery terms an album page shows.
$term_ids = get_post_meta( $post_id, 'album_gallery_terms', true );
if ( ! is_array( $term_ids ) ) {
return $ids;
}
$galleries = get_posts( array(
'post_type' => 'gallery',
'post_status' => 'publish',
'posts_per_page' => -1,
'fields' => 'ids',
'tax_query' => array( array(
'taxonomy' => 'gallerycat',
'field' => 'term_id',
'terms' => array_map( 'intval', $term_ids ),
) ),
) );
foreach ( $galleries as $gid ) {
$thumb = get_post_thumbnail_id( $gid );
if ( $thumb ) {
$ids[] = (int) $thumb;
}
}
return $ids;
}, 10, 2 );
Keeping a CDN host
add_filter( 'image_sitemap_allow_external_host', function ( $allowed, $host ) {
return 'cdn.example.com' === $host ? true : $allowed;
}, 10, 2 );
Caching and limits
| Behaviour | Value |
|---|---|
| Transient TTL | 12 hours |
| URLs per sitemap page | 2,000 |
| Images per URL | 1,000 (Google's ceiling) |
| Response header | X-Robots-Tag: noindex, follow |
The cache is flushed automatically on save_post, deleted_post, attachment
add/edit/delete, term create/edit/delete and switch_theme.
If a page cache sits in front of PHP (LiteSpeed Cache, Cloudflare APO, Varnish, a
CDN), exclude wp-sitemap from it. Otherwise the cache can serve a 404 from before the
plugin was installed, or hold a stale document well past the 12-hour TTL.
Notes
- Page 0 (
/wp-sitemap-images-0.xml) 301s to page 1, matching how core handles its own paged sitemaps, so there is only ever one address per document. - Out-of-range pages return a real 404.
- The registered sitemap provider is a stub. It exists so core mints the URLs and lists
them in the index; rendering happens at
template_redirectpriority 0, beforeWP_Sitemaps::render_sitemaps()can emit an emptyurlset.
License
GPL-2.0-or-later. See LICENSE.