There are three issues in your code:
-
In your custom
wp_attachment_link()
function, you should use the post slug ($attachment->post_name
) instead of simply replacing the-
(dash) in the post title — and note that the resulting slug could be different than the actual slug, e.g. the title could beMy Image
with the actual slug beingmy-image-2
, and yet yourstr_replace()
-ing would result inmy-image
. -
In your rewrite rule, there’s no
$matches[2]
, only$matches[1]
which matches the<slug>
as inexample.com/photos/<slug>
. -
Also in that rule, the query is not valid: You should use the
attachment
parameter and notattachment_id
, so the correct one isattachment=$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
'^photos/([\w\-]+)/?$',
'index.php?attachment=$matches[1]',
'top'
);
} );
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. 🙂