admin管理员组

文章数量:1123509

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" .

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'
];

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'
];
Share Improve this question asked Sep 24, 2016 at 15:27 powerbuoypowerbuoy 8421 gold badge7 silver badges15 bronze badges 5
  • attachment URL output has a filter- attachment_link. you can also add some rewrite rules to handle those /media/attachment-slug/ requests. – Milo Commented Sep 24, 2016 at 15:45
  • I'd prefer to do it the "real" way if you know what I mean. Trying to fake a new URL feels like it will inevitably fail somewhere. – powerbuoy Commented Sep 24, 2016 at 15:49
  • 1 tinkering with the built in post types isn't any more "real" than using the provided filter and API functions, here's some example code from another question. – Milo Commented Sep 24, 2016 at 15:55
  • By real I mean that post types do have the capability to have archives (using has_archive) not only will this give me the correct URL structure it will also (hopefully) create an actual archive page for the images. So yea, it is more real in that sense. Hacking the rewrite rules for attachments and overriding the permalink functions just feels much more like a hack. – powerbuoy Commented Sep 24, 2016 at 15:59
  • If I created my own CPT I wouldn't give it an incorrect URL and no archive only to hack one in with rewrite rules later on. I'd prefer to do the same with the attachments. – powerbuoy Commented Sep 24, 2016 at 16:48
Add a comment  | 

2 Answers 2

Reset to default 0

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);

Here is my solution. First you need to change arguments of attachment post type (as mentioned in the question):

add_filter( 'register_post_type_args', 'change_attachment_post_type_args', 10, 2 );
function change_attachment_post_type_args( $args, $post_type ){
    //Turn on attachment archive page
    if( 'attachment' == $post_type ){
        $args['has_archive']  = 'media';//this is slug
        $args['rewrite']      = true;
    }
    return $args;
}

Then change the post_status to inherit inside WP_Query because default value of post_status is publish but all attachments have inherit status:

add_action( 'pre_get_posts', 'get_all_posts_attachment' , 10, 1);
function get_all_posts_attachment( $query ) {
    if( is_post_type_archive('attachment') && 'attachment' == $query->get('post_type') )
    {
        $query->set( 'post_status', 'inherit' );
    }
    return $query;
}

本文标签: Give attachments an archive page