Make WordPress Core

Opened 16 years ago

Last modified 6 years ago

#8107 new defect (bug)

get_next_post, get_previous_post do not work for posts posted within same second

Reported by: whoismanu's profile whoismanu Owned by:
Milestone: Future Release Priority: normal
Severity: normal Version: 2.7
Component: Posts, Post Types Keywords: needs-testing dev-feedback
Focuses: template Cc:


if you have posts that are published shortly one after the other (e.g. through a script or plugin that posts several posts at once) several of them may end up having the same post_date in the wordpress database table. this is due to the fact that mysql datetime seems to only maintain a precision of one second (see also this discussion:

the problem now is that wordpress functions like get_next_post/get_previous_post (get_adjacent_post resp.) will no longer work correctly if something like this happens as they solely rely on a comparison of the post_date field and they don't treat the case where these timestamps are the same for several posts. the result is that e.g. get_next_post will pick one of the posts having the same timestamp and "jump" over the others, so the user will never see them.

i see two possibilities around this 1.) treat cases with the same post_date by e.g. looking also at the post id (assuming it is always strictly increasing) or probably preferably 2.) make sure that no two posts have the same post_date timestamp by e.g. increasing post_date artificially when publishing the post and if another post already has the same timestamp.

Attachments (2)

8107.patch (1.2 KB) - added by Viper007Bond 15 years ago.
8107.2.patch (1.2 KB) - added by Viper007Bond 15 years ago.
Fix mistype (I had %s instead of %d)

Download all attachments as: .zip

Change History (21)

#1 @Denis-de-Bernardy
15 years ago

  • Keywords needs-patch added; post_date get_next_post datetime removed
  • Milestone changed from 2.8 to Future Release

#2 @Viper007Bond
15 years ago

  • Component changed from General to Template
  • Severity changed from normal to minor

Ooof, unless I'm missing something, this is a tricky patch.

The trick is to change the older/newer operator to older/newer OR exact same time AND not the same post ID. That makes the same-time post show up in the next/prev links, but the problem is you then get stuck in a loop, i.e. you go from post A to post B and back to post A. You also can't do a less-than/greater-than on the ID because IDs don't necessarily correspond to the datetime (i.e. you could have older posts with IDs both higher and lower than the current post).

As I said, seems to be pretty hard to get it not stuck in a loop.

#3 @Denis-de-Bernardy
15 years ago

  • Keywords 2nd-opinion added; needs-patch removed

I'd say wontfix/plugin material.

the case would only arise when the publishing of posts is automated. it can, and should, be dealt with by whichever tool is used to publish the post in the first place -- it makes no sense to publish two posts in one go anyway...

#4 @DD32
15 years ago

It could also be caused by publishing a group of drafts via QuickEdit too i think.

A 2-part conditional such as this could work however

(IRC) DD32	Needs to have an order with an ID, and a conditional for ( ( postdate == now && ID < currentID ) || postdate < now)

15 years ago

#5 @Viper007Bond
15 years ago

See patch. :)

Two minds are indeed better than one. Props DD32 for the inspiration.

#6 @Viper007Bond
15 years ago

  • Keywords has-patch needs-testing added; 2nd-opinion removed

15 years ago

Fix mistype (I had %s instead of %d)

#7 @Denis-de-Bernardy
15 years ago

  • Milestone changed from Future Release to 2.9
  • Priority changed from normal to low

#8 @ryan
15 years ago

  • Milestone changed from 2.9 to Future Release

#9 @Viper007Bond
14 years ago

  • Milestone changed from Future Release to 3.1

Let's finally test this and fix this.

#10 @nacin
14 years ago

  • Milestone changed from Awaiting Triage to Future Release

Marked #12650 as a duplicate. Is this patch still good? I noted in the other ticket that I'm not sure you can rely on the ID, but it's better than skipping the post all together.

#11 @salcode
11 years ago

  • Cc salcode added

#12 @nacin
10 years ago

  • Component changed from Template to Posts, Post Types
  • Focuses template added

#13 @billerickson
10 years ago

no, this patch is no longer good due to the introduction of WP_Adjacent_Post in #26937

#14 follow-up: @billerickson
10 years ago

  • Keywords dev-feedback added; has-patch removed

In versions 3.8 and less, when using previous/next post links any posts with the same published date and time as the current post are skipped.

In version 3.9, you get stuck in a loop, going back and forth between posts in the same date. This is because the date_query has 'inclusive' => true and we're excluding the current post.

I played around with it a bit and couldn't come up with a single WP Query that queried either posts ordered by date with different published dates OR posts ordered by ID with the same published date. Doing 'orderby' => 'date ID' didn't do it.

I think we might need to do multiple queries. Keep the current one, but before we return the adjacent post, check to see if the date matches the current post. If it does, query for posts with that same date, sorted by post ID (to end the loop we're in). If no results for that, do the original adjacent post query but set 'inclusive' => false.

I'm happy to write the patch, but that's a lot of queries. Is there a more efficient approach?

Last edited 10 years ago by billerickson (previous) (diff)

#15 @Viper007Bond
10 years ago

You shouldn't need multiple queries, especially for an edge case like this (not worth adding more queries for 0.0001% of cases). I got it working with just one via my patch. We should be able to come up with some solution using WP_Query, even if we have to add functionality to WP_Query.

Last edited 10 years ago by Viper007Bond (previous) (diff)

#16 in reply to: ↑ 14 @SergeyBiryukov
10 years ago

Replying to billerickson:

I played around with it a bit and couldn't come up with a single WP Query that queried either posts ordered by date with different published dates OR posts ordered by ID with the same published date. Doing 'orderby' => 'date ID' didn't do it.

'order' => 'ASC', 'orderby' => 'date ID' with a subsequent array_reverse() would probably work, see comment:14:ticket:26042 and 26042.3.diff:ticket:26042.

#17 @billerickson
10 years ago

What would the array_reverse() be applied to? We're querying for a single post ( 'posts_per_page' => 1 ).

If you have two posts with the same datetime, then the adjacent post will always be the other one. Key query_vars:

'posts_per_page' => 1,
'post__not_in' => array( $this->current_post->ID ),
'date_query' => array(
      $date_query_key => $this->current_post->post_date,
      'inclusive' => true,

Whether you're looking for previous or next, both posts will be included due to the inclusive line. And since we're excluding the current post, the other post will always be returned.

#18 @chriscct7
9 years ago

  • Priority changed from low to normal
  • Severity changed from minor to normal

#19 @billerickson
6 years ago

This bug still exists in WordPress 5.0.

Steps to reproduce:

  1. Publish at least one post (ex: Hello World!)
  2. Create three draft posts (ex: Sample Post 1, 2, 3)
  3. Select all three draft posts, then Bulk Actions > Edit. Change Status to "Published"
  4. When viewing any of the recently published posts, the previous post link skips the other posts published at the same time.

In my case, when viewing Sample Post 2, the previous post is Hello World (skipping Sample Post 1) and there is no next post (skipping Sample Post 3)

Note: See TracTickets for help on using tickets.