How to Customize the URL of Attachments in WordPress

Using a custom URL structure for attachment pages gives a nice touch to your website.

Problem

You need to create a custom URL structure for attachments. The slug of each attachment must end with a suffix, so the slug derived from the filename remains free.

Example: If you upload the file Landscape.png to the Media Library, the URL of the attachment page should be https://example.com/media/landscape-dl.

Theory

In the next section I propose a solution that uses the 'rewrite_rules_array' filter to add a rewrite rule, so WordPress knows how to process the custom URL structure.

The 'attachment_link' filter is used to customize the attachment URL according to the new structure. The 'wp_insert_attachment_data' filter is used to append a suffix to the slug if the suffix is not present yet.

Steps

Follow these steps to solve the problem described previously.

Step 1: Add the code below to WordPress. Adjust the variables $dirname and $suffix as desired.

Step 2: Navigate to Settings > Permalinks. Click Save Changes to flush rewrite rules.

Step 3: Upload a file to the Media Library and visit the attachment page. Verify that the URL is as expected.

/*
 * Adds custom rewrite rules.
 */
function ns_add_rewrite_rules($rules){
    
    $dirname = 'media';
    $custom_rules = array("{$dirname}/(.?.+?)/?$" => 'index.php?attachment=$matches[1]');
    return array_merge($custom_rules, $rules);
}
add_filter('rewrite_rules_array', 'ns_add_rewrite_rules', 10, 1);

/*
 * Adds the 'media' directory to the URL of an attachment.
 */
function ns_normalize_attachment_url($url, $post_ID){
    
    $dirname = 'media';
    $post = get_post($post_ID);
    return $post ? sprintf('%s/%s/%s/', home_url(), $dirname, $post->post_name) : $url;
}
add_filter('attachment_link', 'ns_normalize_attachment_url', 10, 2);

/*
 * Adds the '-dl' suffix to the name of an attachment.
 */
function ns_normalize_attachment_name($data, $postarr){
    
    $suffix = '-dl';
    $has_suffix = substr($data['post_name'], -strlen($suffix)) === $suffix;
    $add_suffix = isset($postarr['ID']) && !$has_suffix;
    
    if($add_suffix){
        $desired_name = $data['post_name'] . $suffix;
        $data['post_name'] = wp_unique_post_slug($desired_name, $postarr['ID'], $data['post_status'], $data['post_type'], $data['post_parent']);
    }
    return $data; 
}
add_filter('wp_insert_attachment_data', 'ns_normalize_attachment_name', 10, 2);

Discussion

Each attachment is now accessible through the custom URL and the default URL works too. There is no risk from an SEO viewpoint since WordPress sets the canonical URL to the custom URL.

Attachments created before this change will not have the suffix in the slug. If you want the suffix in these attachments, open the edit screen of each one and click the Update button. Note that existing links may get broken.

Further reading

I recommend the other tutorials in this series to learn more about managing attachments in WordPress.

Source code

The source code developed in this tutorial is available here.