The WordPress Attachment Page redirect loop

Looking through my server logs I noticed how Baidu’s web spider was causing an unexpected redirect loop while trying to index an image attachment page. Since I deliberately redirect all attachment page requests to the actual post owning the attachment, I decided to take a closer look. The following request triggered the loop:

GET /arch-pacstrap/ HTTP/1.1" 302 - "-"
GET /arch-pacstrap/ HTTP/1.1" 302 - "-"
GET /arch-pacstrap/ HTTP/1.1" 302 - "-"
GET /arch-pacstrap/ HTTP/1.1" 302 - "-"
…

After logging into WordPress and locating the offending arch-pacstrap image, the problem became obvious. The image was unattached (meaning it didn’t belong to a post) and thus I was redirecting Baidu’s web spider to the same page over and over. The issue was caused by the following code from my image.php template:

wp_redirect(get_permalink($post->post_parent));
exit;

The issue with this code is that the $post->post_parent value will be 0 when an image (or any other attachment) is/becomes unattached. This causes the get_permalink() function to return the permalink for the requested URL instead. And that’s how you code your very own redirect loop.

The fix is simple, we need to check if $post->post_parent has a value before performing the redirect. If not, then let’s redirect to the home page instead. I also want to send a 301 (moved permanently) status message to the client instead of returning the default 302 (found) message. I’ll add the following code to my image.php template in the theme folder to implement this functionality:

$redirect = ($post->post_parent) ? get_permalink($post->post_parent) : home_url();
wp_safe_redirect($redirect, 301);
exit;

Please refer to the WordPress template hierarchy on how to identify the correct template to modify based on attachment type.