6

I am experiencing some odd behavior, that apparently happens "out of the box" with WordPress.

If I upload a file through the media manager called: services.jpg; then go try to create a page with the permalink http://example.com/services/; The slug services-2 is given instead, because the attachment is already using that slug.

Visiting http://example.com/services/ loads the attachment page.

I have not enabled any plugins or added anything into functions.php to modify the rewrites for attachments.

Has anyone run into this before? Know where to start to disable this functionality?

2
  • 1
    This is standard functionality from WordPress Core, posts cannot have the same slugs, regardless of post type ( attachments are posts too, of type attachment, as are pages which are of type page ). This is to prevent clashes. There are some bits of code that might help, but I'm unfamiliar with the specifics. Also, this is something that will eventually be fixed in Core, or at least have some sort of solution, Eitherway the problem is ambiguity, what if you have a post type services a page called services and a normal post, and you set your permalinks to only have the name?
    – Tom J Nowell
    Feb 24, 2015 at 0:21
  • Fixing it for everybody is a non trivial problem
    – Tom J Nowell
    Feb 24, 2015 at 0:22

4 Answers 4

5

Thank you for the response everyone. I played around with macemmek's solution and I think it led me to an even better solution:

add_filter( 'wp_unique_post_slug_is_bad_attachment_slug', '__return_true' );

That is all that is needed. This will automatically 'skip' the default assigned slug on any attachment. So an attachment that might normally get the slug "services" will now get the slug "services-2".

8
  • Perfect and elegant for a conscious admin, so +1. However, it is possible that some user trashes "services" blog post and creates another one which will get "services-2" slug and we have 2 items slugged "services-2". My clients do this always. ;) Feb 24, 2015 at 22:23
  • Actually based on the code I am seeing, WP would attempt to give out services-2, however if it is taken like in your example, it will then try -3, -4, -5, etc until it finds a unique slug.
    – Matt Keys
    Feb 24, 2015 at 22:29
  • I've tried this. I have two "services-2" posts in the database, really. Feb 24, 2015 at 22:38
  • Very strange, I can't reproduce that behavior you are seeing. I just tested it out on WordPress 4.1.1. If services-2 slug already exists, the new attachment gets the slug services-3. Which lines up with the expected behavior that I am seeing in the do while function here in the codebase: core.trac.wordpress.org/browser/tags/4.1.1/src/wp-includes/… If you are able to reproduce the steps that led to a duplicate slug being produced, we could submit a ticket to the WordPress core bug tracker.
    – Matt Keys
    Feb 24, 2015 at 23:59
  • 2
    I haven't looked at the latest code but I think the issue is in the handling of post types in wp_unique_post_slug(). The SQL query is only searching within the same post-type so it will not check for a collision with attachments.
    – KenB
    Feb 27, 2015 at 15:31
4

You may hook wp_unique_post_slug() and append some string to the original slug if the post is an attachment type. The original slug based on post title will remain free.

UPDATED after Rachel Baker's comment: original slug suffix is some random string. It does not guarantee uniqueness but may be enough for simple use cases.

add_filter( 'wp_unique_post_slug', 'wpse17916_unique_post_slug', 10, 6 );
function wpse17916_unique_post_slug( $slug, $post_ID, $post_status, $post_type, $post_parent, $original_slug ) {
  if ( 'attachment' == $post_type )
    $slug = $original_slug . uniqid( '-' );
  return $slug;
}
5
  • Interesting idea
    – Tom J Nowell
    Feb 24, 2015 at 14:41
  • 3
    The wp_unique_post_slug filter is a great solution, however it can also cause issues if not used carefully. There would still need to be a condition added that checks if the $original_slug variable is unique among the attachment posts to prevent conflicts. Feb 24, 2015 at 14:55
  • 1
    Right. I've improved the answer with uniqid() suffix. I'm aware that full and bulletproof solution should check uniqueness in DB. Feb 24, 2015 at 17:11
  • This is a good solution, although looking through the wp_unique_post_slug() function I think I found an even cleaner solution to this problem. See my answer for details.
    – Matt Keys
    Feb 24, 2015 at 20:34
  • You're right but then the uniqueness can be broken from another side: blog post. (See my comment) Feb 24, 2015 at 22:26
1

Tom's comment is correct, in that this is normal behaviour and there is not much you can do to stop it.

But you can change slugs after things are uploaded/created. While you shouldn't do this if the links are known/publicised/listed on search engines, if you're just trying to fix this problem occasionally after an upload then you can edit the slug of the attachment (to be something like services-attachment), and then edit the slug of the page to be services.

To do this, go to Media, click Edit under the attachment you want to edit (or if on grid view, click the attachment then click Edit more details), then at the top you'll see the permalink.. clicking Edit here will let you change the slug.

Then repeat the same process for the page itself.

0

I think what you need to do here is use a redirect to prevent people from seeing the media items. It's a good fit with the other solutions presented here. Prepend something to the media item slugs, the write a redirect to 'get rid' of the media pages.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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