I am creating a gallery site using FooGallery and having the individual images open in the attachment page. I tried a bunch of codes from here to rewrite the attachment urls from ?attachment_id=8184 to /photos/frienly url but they are not working properly.

This code below works but it is not stable. If it works for one image, few hours later it starts redirecting to the homepage.

Any help on fixing this permanently?

add_filter( 'attachment_link', 'wp_attachment_link', 20, 2 );
function wp_attachment_link( $link, $attachment_id ){
$attachment = get_post( $attachment_id );
$attachment_title = $attachment->post_title ;
$attachment_title = str_replace( ' ' , '-' , $attachment_title );
$site_url = get_site_url( $attachment_id );
$link =  $site_url . '/photos/'  .$attachment_title;
return $link;
// Rewrite attachment page link
add_action( 'init', function() {
add_rewrite_rule( 'photos/([A-Za-z0-9-]+)?$', 'index.php?attachment_id=$matches[2]', 'top' );

1 Answer 1


There are three issues in your code:

  1. In your custom wp_attachment_link() function, you should use the post slug ($attachment->post_name) instead of simply replacing the (whitespaces) with - (dash) in the post title — and note that the resulting slug could be different than the actual slug, e.g. the title could be My Image with the actual slug being my-image-2, and yet your str_replace()-ing would result in my-image.

  2. In your rewrite rule, there's no $matches[2], only $matches[1] which matches the <slug> as in example.com/photos/<slug>.

  3. Also in that rule, the query is not valid: You should use the attachment parameter and not attachment_id, so the correct one is attachment=$matches[1].

So that should help you fix your own code, or you can try my code:

add_filter( 'attachment_link', 'wp_attachment_link', 20, 2 );
function wp_attachment_link( $link, $attachment_id ) {
    if ( ! $slug = get_post_field( 'post_name', $attachment_id ) ) {
        return $link; // you should just do this if the slug is empty..

    return home_url( user_trailingslashit( "/photos/$slug", 'single' ) );

// Rewrite attachment page link.
add_action( 'init', function() {
    add_rewrite_rule( // wrapped for brevity
} );

And don't forget to flush the rewrite rules; just visit the permalink settings admin page (wp-admin → Settings → Permalinks). Also, you should use a unique function name and not wp_attachment_link, e.g. use my_prefix_attachment_link. :)

  • Sorry, I made a mistake and I've revised my answer - basically, use the same code I provided before, but use index.php?attachment=$matches[1] with the add_rewrite_rule(). And that should work as expected, but let me know.
    – Sally CJ
    Feb 3, 2021 at 7:50
  • 1
    Yes. This works! Thank you so much. Been struggling with this for a week and couldn't get this sorted. You are a saviour! Feb 3, 2021 at 8:16
  • So would you mind marking my answer as correct? :)
    – Sally CJ
    Feb 3, 2021 at 8:30
  • 1
    I did that :) and removed the other comments to make it relevant. Feb 3, 2021 at 9:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.