Give attachments an archive page

I’m trying to override WP’s default URL structure for attachments where, if they’re attached to a post, the URL is /post-slug/attachment-slug/ and if not it’s simply /attachment-slug/.

What I’d like instead is for attachments to behave like posts in that they have an archive and all URLs point to /archive-slug/attachment-slug/.

I’ve found a new (with 4.4 I believe) filter that allows you to modify post type options but it doesn’t seem to work as advertised;

add_filter('register_post_type_args', function ($args, $postType) {
    if ($postType == 'attachment'){
        $args['has_archive'] = true;
        $args['rewrite'] = [
            'slug' => 'media'
        ];
    }

    return $args;
}, 10, 2);

If I var_dump($args) they do in fact look correct (has_archive is true etc) but it doesn’t appear to have any effect on the URLs at all.

This might not be very surprising if this comment by the devs is correct; “Does not apply to built-in post types” https://core.trac.wordpress.org/changeset/34242.

So my question is how can I still accomplish this?

I’ve also tried just modifying the post type object in the init hook, but it won’t bite:

$obj = get_post_type_object('attachment');

$obj->has_archive = true;
$obj->rewrite = [
    'slug' => 'media'
];

2 Answers
2

This is untested, so apologies there, but I’m thinking out loud, have you tried re-registering the post type afterwards? Or flushed rewrite rules after your initial attempt with flush_rewrite_rules();?

function change_attachment_post_type() {

    $args = get_post_type_object('attachment');
    $args->has_archive = true;
    $args->rewrite = [
        'slug' => 'media'
    ];
    register_post_type($args->name, $args);

    // As a temporary one time, remove after first flush
    flush_rewrite_rules();
}
add_action('init', 'change_attachment_post_type', 20);

Leave a Comment