WordPress.org

Make WordPress Core

Opened 7 years ago

Last modified 3 months ago

#13459 accepted defect (bug)

Conflict between post and page slugs/permalinks when permalink setting is set to /%postname%/

Reported by: jamescollins Owned by: ericlewis
Milestone: Future Release Priority: normal
Severity: normal Version: 2.9.2
Component: Permalinks Keywords: has-patch
Focuses: Cc:

Description

If Dashboard -> Settings -> Permalinks is set to /%postname%/, it is possible to create both a page and a post with the same slug. When viewing via the frontend, the page is always displayed.

I would have thought that WordPress should prevent a post and a page from having the same permalink.

Steps to reproduce:

  1. Create and publish a page with any slug. eg. http://domain.com/test/.
  2. Create and publish a blog post with the same slug. Wordpress says the permalink for the blog post is http://domain.com/test/, but when you visit that URL it displays the page instead.

I can reproduce this on my 2.9.2 install, as well as 3.0 trunk. I'm guessing the bug is present in earlier versions of WordPress as well.

Possibly related: #11863

Attachments (9)

13459.patch (1.2 KB) - added by SergeyBiryukov 4 years ago.
13459.2.patch (1.1 KB) - added by moraleida.me 3 years ago.
Exact same patch from SergeyBiryukov, reapplied to current codebase
13459-unit-tests-post.php.patch (1.0 KB) - added by moraleida.me 3 years ago.
post.php.patch (537 bytes) - added by datta.parad 2 years ago.
13459.diff (3.2 KB) - added by MikeHansenMe 23 months ago.
13459-w-test.diff (5.8 KB) - added by MikeHansenMe 23 months ago.
13459.2.diff (5.6 KB) - added by ericlewis 12 months ago.
13459.3.diff (6.2 KB) - added by ericlewis 12 months ago.
13459.4.diff (7.8 KB) - added by ericlewis 12 months ago.

Download all attachments as: .zip

Change History (65)

#1 @solarissmoke
6 years ago

  • Keywords dev-feedback added

I feel like there is another ticket for this, but can't find it.

In any case, I can't see any easy way to fix this, because pages are allowed to have non-unique slugs across hierarchies. One possibility might be to check for this particular permalink structure and modify the unique slug generation accordingly to ensure that no pages have that slug - but it would only work for new/updated posts - old ones would still have a conflict. Bit flimsy.

#2 follow-up: @stephencronin
6 years ago

This problem still occurs in 3.1.1.

It persists even after the Page is sent to Trash (the user gets a 404 instead of the Post), until the Page is emptied from the Trash.

The suggestion by solarissmoke is better than nothing. Ideally it would have to work both ways, ie if permalink is /%postname%/ then:

1) check that no posts have this slug when generating top level page slug
2) check that no top level pages have this slug when generating post slug

It may not cover everything:

a) it may not just be posts and pages we have to worry about (some people strip /category/ from URL for category pages for example);
b) there is a very small chance that /%category%/%postname%/ posts could clash with a second level page.

but they are real edge cases and as I said, it's better to do something than nothing.

#4 @SergeyBiryukov
4 years ago

#23166 was marked as a duplicate.

#5 in reply to: ↑ 2 @SergeyBiryukov
4 years ago

Replying to stephencronin:

It persists even after the Page is sent to Trash (the user gets a 404 instead of the Post), until the Page is emptied from the Trash.

#21970 would fix that.

#6 @ocean90
4 years ago

#23300 was marked as a duplicate.

#7 @markoheijnen
4 years ago

Seriously, till now we never fixed this. That's quite a shame.

#8 @ocean90
4 years ago

  • Keywords needs-patch added; dev-feedback removed

#9 @markoheijnen
4 years ago

#23300 was marked as a duplicate.

#10 follow-up: @SergeyBiryukov
4 years ago

  • Keywords dev-feedback added

wp_unique_post_slug() returns a unique slug within the given post type.

Seems like we have 3 options:

  1. Always prevent posts, pages (and CPTs?) from having the same slug (require unique slugs across all post types). Since having the same slug is actually fine with most permalink structures, this sounds like an unnecessary restriction.
  2. Only do the above for the /%postname%/ permalink structure. However, if the structure changes to /%postname%/ later (after the page and the post are created), we'll still end up with a conflict.
  3. Leave this to a plugin, since wp_unique_post_slug() is filterable (#14111).

I personally think that the permalink conflict is to be expected in this case, so the 3rd option sounds acceptable to me.

#11 in reply to: ↑ 10 @SergeyBiryukov
4 years ago

Replying to SergeyBiryukov:

wp_unique_post_slug() returns a unique slug within the given post type.

Correction: As noted in comment:1, pages are allowed to have non-unique slugs across hierarchies:
http://core.trac.wordpress.org/browser/tags/3.5/wp-includes/post.php#L3103

#12 @markoheijnen
4 years ago

I disagree with leaving this to a plugin. The problem is only for post vs pages when the permalink structure is "/%postname%/".

It seems for me that the 2nd option is the way to go. Obviously changing to the structure will ending up with a conflict but that can be plugin territory.

#13 @SergeyBiryukov
4 years ago

  • Keywords has-patch added; needs-patch removed
  • Milestone changed from Future Release to 3.6

13459.patch is an attempt to implement option 2.

#14 @SergeyBiryukov
4 years ago

  • Keywords needs-unit-tests added

@moraleida.me
3 years ago

Exact same patch from SergeyBiryukov, reapplied to current codebase

#15 @moraleida.me
3 years ago

Simple unit test added to cover the case when the same title is used to create a post and a page AND permalinks are set to /%postname%/

#16 @moraleida.me
3 years ago

  • Cc moraleida.me added

#17 @markjaquith
3 years ago

  • Milestone changed from 3.6 to Future Release

Just checking for '/%postname%/' isn't going to cover it completely. Will at least need to standardize trailing slashes on that check. Let's take a look at this early in 3.7.

#18 @context
3 years ago

  • Cc context added

#19 follow-up: @Ipstenu
3 years ago

It appears this is no longer restricted to JUST using /%postname%/ as your permalink.

On 3.8 and 3.9-alpha I can make both a page and a post with the same slug. Using /%year%/%postname%/

#20 in reply to: ↑ 19 @digiscience
3 years ago

For me this is a feature, not a bug. I can place pages into blog lists. Very useful, hope you'll never fix it.

#22 @jeremyfelt
3 years ago

#27297 was marked as a duplicate.

#23 @ryan
2 years ago

  • Owner ryan deleted
  • Status changed from new to assigned

#24 @SergeyBiryukov
2 years ago

#28900 was marked as a duplicate.

#25 @datta.parad
2 years ago

Actually needs to change parameter of get_post_types function, currently it only return "page" Post type.

#26 @SergeyBiryukov
2 years ago

#28960 was marked as a duplicate.

@MikeHansenMe
23 months ago

#27 @MikeHansenMe
23 months ago

It also depends which order the page/post is created. So we need to check the permalink structure in both hierarchical and non-hierarchical.

#28 @MikeHansenMe
23 months ago

  • Keywords needs-unit-tests removed

Added some tests to ensure it is working when different combinations of post/page are made.

#29 @SergeyBiryukov
21 months ago

#31704 was marked as a duplicate.

#30 @SergeyBiryukov
19 months ago

#32426 was marked as a duplicate.

#31 @SergeyBiryukov
16 months ago

#32795 was marked as a duplicate.

#32 @SergeyBiryukov
16 months ago

  • Milestone changed from Future Release to 4.4

See comment:1:ticket:32795 for potential options.

This ticket was mentioned in Slack in #core by sergey. View the logs.


15 months ago

#34 @SergeyBiryukov
15 months ago

  • Owner set to SergeyBiryukov
  • Status changed from assigned to reviewing

#35 @helen
14 months ago

#23166 was marked as a duplicate.

#36 @helen
14 months ago

#23166 was marked as a duplicate.

#37 @SergeyBiryukov
14 months ago

Since [34690], attachments now have pretty permalinks too.

This increases the chances of clashing with post slugs, see #24612 and comment:8:ticket:24612.

We should make sure that attachments and posts cannot have duplicate slugs if /%postname%/ structure is used.

#38 @SergeyBiryukov
14 months ago

For reference, some of this functionality may (or may not) have changed in #18962.

This ticket was mentioned in Slack in #core by sergey. View the logs.


14 months ago

#40 @QROkes
13 months ago

Subdirectory multisite could clash also and may be related with 12002 (Closed and included in 4.4 next release).

#41 @wonderboymusic
13 months ago

  • Keywords needs-refresh added; dev-feedback removed

@SergeyBiryukov the patch is exploding, do we need to do this in 4.4?

This ticket was mentioned in Slack in #core by wonderboymusic. View the logs.


13 months ago

#43 @wonderboymusic
13 months ago

  • Milestone changed from 4.4 to Future Release

@ericlewis
12 months ago

@ericlewis
12 months ago

#44 @ericlewis
12 months ago

  • Keywords needs-refresh removed

I've added a few changes in attachment:13459.3.diff.

  • Consolidate the checks into a single query rather than two. The extra check we want to perform is to confirm uniqueness across more post types, which we can do with an IN.
  • Avoid post and attachment slug collisions as Sergey suggested.

@ericlewis
12 months ago

#45 @ericlewis
12 months ago

In attachment:13459.4.diff

  • Moved the tests to wpUniquePostSlug.php
  • Added tests for post slug/attachment slug collisions. A post slug can't collide with an attachment slug when the permalink structures are the same, but they can collide when the permalink structures are different.

#46 @SergeyBiryukov
12 months ago

Seems like '/%postname%/' === $wp_rewrite->permalink_structure won't catch a static prefix, e.g. '/blog/%postname%/'. Would that still cause a conflict if there's a 'Blog' page with subpages?

Perhaps the preg_match() check from [35679] could be used.

Last edited 12 months ago by SergeyBiryukov (previous) (diff)

#47 @ericlewis
12 months ago

Seems like '/%postname%/' === $wp_rewrite->permalink_structure won't catch a static prefix, e.g. '/blog/%postname%/'. Would that still cause a conflict if there's a 'Blog' page with subpages?
Perhaps the preg_match() check from [35679] could be used.

We can drop this into our logic for looking up a unique slug for a post (post_type = post). This would be complex to use for page slugs, because that query ensures uniqueness is tied to diffferent post_parent levels / URL path hunks.

Do you think that's a must-fix use-case for this issue, or an edge case? This is not the only collision of this flavor we will see, e.g. %tax_base%/%tax_term% collisions with a subpage.

#48 @ericlewis
12 months ago

  • Owner changed from SergeyBiryukov to ericlewis
  • Status changed from reviewing to accepted

#49 @ericlewis
12 months ago

@SergeyBiryukov said:

Seems like '/%postname%/' === $wp_rewrite->permalink_structure won't catch a static prefix, e.g. '/blog/%postname%/'. Would that still cause a conflict if there's a 'Blog' page with subpages?

I've created a plugin to approach the problem in a more holistic way — Cool slugs. It uses the rewrite API to determine if a URL namespace is already occupied. This has the potential to avoid all problems of this nature. What do you think?

cc @boonebgorges, who also has a natural affinity to wp_unique_post_slug().

#50 @ericlewis
12 months ago

  • Keywords needs-patch good-first-bug added; has-patch removed

#51 @ericlewis
12 months ago

  • Keywords has-patch added; needs-patch good-first-bug removed

This ticket was mentioned in Slack in #core by eric. View the logs.


11 months ago

#53 @Reiniepress
8 months ago

Can i use that "plugin" until someone decides to release the/a fix ?
(not sure I can ask here...)
Thanks.

Last edited 8 months ago by Reiniepress (previous) (diff)

This ticket was mentioned in Slack in #core by helen. View the logs.


7 months ago

#55 @ocean90
3 months ago

#38005 was marked as a duplicate.

#56 @peterwilsoncc
3 months ago

#38022 was marked as a duplicate.

Note: See TracTickets for help on using tickets.