-
Notifications
You must be signed in to change notification settings - Fork 3.2k
get_adjacent_post: adjacent post query plugin compatibility #10620
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: trunk
Are you sure you want to change the base?
get_adjacent_post: adjacent post query plugin compatibility #10620
Conversation
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the Core Committers: Use this line as a base for the props when committing in SVN: To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
Test using WordPress PlaygroundThe changes in this pull request can previewed and tested using a WordPress Playground instance. WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser. Some things to be aware of
For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added a few notes inline.
|
|
||
| remove_all_filters( 'get_next_post_where' ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Test suite does this automatically so it can be removed.
🔢 Applies in the tests below so I won't repeat myself.
| remove_all_filters( 'get_next_post_where' ); |
| // Next post should be the 4th post (higher ID, same date) - deterministic. | ||
| $next = get_adjacent_post( false, '', false ); | ||
| $this->assertInstanceOf( 'WP_Post', $next ); | ||
| $this->assertEquals( $post_ids[3], $next->ID ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| $this->assertEquals( $post_ids[3], $next->ID ); | |
| $this->assertSame( $post_ids[3], $next->ID ); |
🔢 Looks to apply elsewhere so I won't repeat myself.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍🏻
src/wp-includes/link-template.php
Outdated
|
|
||
| // Only force deterministic fallback if the where clause has not been modified by a filter. | ||
| if ( $where === $where_prepared ) { | ||
| $where = $where_prepared_with_deterministic_fallback; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any particular reason you're defining $where_prepared_with_deterministic_fallback above rather than here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm trying to reduce my carbon footprint by limiting my Ctrl+V and Ctrl+P ![]()
No reason at all actually. I can move.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I knew there was a better reason than that 😄
I wanted to use the original $where (with post_status conditions) without having to store it in a new var before the filter.
src/wp-includes/link-template.php
Outdated
| * @param string $order Sort order. 'DESC' for previous post, 'ASC' for next. | ||
| */ | ||
| $sort = apply_filters( "get_{$adjacent}_post_sort", "ORDER BY p.post_date $order, p.ID $order LIMIT 1", $post, $order ); | ||
| $sort_prepared = "ORDER BY p.post_date $order LIMIT 1"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will need to be done above the docblock so docs-parsers can figure out the filter it applies to.
src/wp-includes/link-template.php
Outdated
| * @since 4.4.0 Added the `$taxonomy` and `$post` parameters. | ||
| * @since 6.9.0 Adds ID-based fallback for posts with identical dates in adjacent post queries. | ||
| * | ||
| * @param string $where The `WHERE` clause in the SQL. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yours truly missed this last time.
| * @param string $where The `WHERE` clause in the SQL. | |
| * @param string $where_prepared The `WHERE` clause in the SQL. |
src/wp-includes/link-template.php
Outdated
| * Can either be next or previous post. | ||
| * | ||
| * @since 2.5.0 | ||
| * @since 6.9.1 Adds deterministic fallback for sort clause if not modified by a filter. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should probably include the since changes for 6.0.0 that yours truly also missed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What are they? 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe something like this?
| * @since 6.9.1 Adds deterministic fallback for sort clause if not modified by a filter. | |
| * @since 6.9.0 Introduce deterministic fallback based in IDs to account for date collisions. | |
| * @since 6.9.1 Remove deterministic fallback for sites modifying the WHERE clause via a filter. | |
| * See https://core.trac.wordpress.org/ticket/64390 |
|
Thanks @peterwilsoncc I'll fix those things up next week. |
src/wp-includes/link-template.php
Outdated
| // Prepare the where clause for the adjacent post query. | ||
| $where_prepared = $wpdb->prepare( "WHERE (p.post_date $comparison_operator %s OR (p.post_date = %s AND p.ID $comparison_operator %d)) AND p.post_type = %s $where", $current_post_date, $current_post_date, $post->ID, $post->post_type ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $comparison_operator is a string literal, either '<' or '>'. | ||
|
|
||
| $where_prepared_with_deterministic_fallback = $wpdb->prepare( "WHERE (p.post_date $comparison_operator %s OR (p.post_date = %s AND p.ID $comparison_operator %d)) AND p.post_type = %s $where", $current_post_date, $current_post_date, $post->ID, $post->post_type ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $comparison_operator is a string literal, either '<' or '>'. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This variable is quite long. How about just $deterministic_where_prepared?
…ery hasn't been modified. This update introduces a deterministic fallback for the SQL `WHERE` and `ORDER BY` clauses in the `get_adjacent_post` function when posts have identical dates. The fallback is applied only if the respective clauses have not been modified by filters, ensuring consistent behavior. Unit tests have been added to verify the correct application of this fallback under various conditions, including scenarios where filters are applied or not. See Trac ticket https://core.trac.wordpress.org/ticket/64390.
Unit tests have been updated according to feedback (using assertSame for simple comparisons), and removing filter removes.
199f7e2 to
f001ac2
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This pull request enhances the adjacent post navigation feature (introduced in PR #10394) to be more defensive and plugin-friendly. It ensures that when plugins modify the get_{$adjacent}_post_where or get_{$adjacent}_post_sort filters, the deterministic ID-based ordering logic is not applied on top of their modifications.
Changes:
- Modified filter application order to pass original (non-deterministic) SQL clauses to filters first
- Added conditional logic to only apply deterministic WHERE/SORT clauses when filters don't modify the original clauses
- Added comprehensive test coverage for the new conditional behavior
- Updated documentation to reflect the changes in version 6.9.1
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 10 comments.
| File | Description |
|---|---|
| src/wp-includes/link-template.php | Modified get_adjacent_post() to conditionally apply deterministic ID-based ordering only when filters don't modify WHERE/SORT clauses; updated documentation |
| tests/phpunit/tests/link/getAdjacentPost.php | Added 5 new test methods to verify deterministic logic is applied/skipped based on filter modifications |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| * | ||
| * @since 2.5.0 | ||
| * @since 6.9.0 Introduce deterministic fallback based in IDs to account for date collisions. | ||
| * @since 6.9.1 Remove deterministic fallback for sites modifying the WHERE clause via a filter. See #64390. |
Copilot
AI
Jan 20, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The documentation states "Remove deterministic fallback for sites modifying the WHERE clause" but the code only removes it when the WHERE filter is modified. The SORT clause is handled separately. Consider updating to "Remove deterministic fallback for sites modifying the WHERE or SORT clause via filters" to be more accurate about what this version changes.
| * @since 6.9.1 Remove deterministic fallback for sites modifying the WHERE clause via a filter. See #64390. | |
| * @since 6.9.1 Remove deterministic fallback for sites modifying the WHERE or SORT clause via filters. See #64390. |
| * @since 6.9.0 Adds ID-based fallback for posts with identical dates in adjacent post queries. | ||
| * | ||
| * @param string $where The `WHERE` clause in the SQL. | ||
| * @param string $where_prepared The `WHERE` clause in the SQL. |
Copilot
AI
Jan 20, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The parameter name in the docblock was changed from "$where" to "$where_prepared", but this parameter represents the actual value passed to the filter (the prepared WHERE clause). However, this is a breaking change to the filter documentation. Plugins that read the documentation would expect the parameter to be named "$where" as it has been historically. Consider keeping the parameter name as "$where" in the docblock for consistency with the historical API, even though internally the variable is named "$where_prepared".
| * @param string $where_prepared The `WHERE` clause in the SQL. | |
| * @param string $where The `WHERE` clause in the SQL. |
| * Can either be next or previous post. | ||
| * | ||
| * @since 2.5.0 | ||
| * @since 6.9.0 Introduce deterministic fallback based in IDs to account for date collisions. |
Copilot
AI
Jan 20, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo in documentation: "based in IDs" should be "based on IDs".
| * @since 6.9.0 Introduce deterministic fallback based in IDs to account for date collisions. | |
| * @since 6.9.0 Introduce deterministic fallback based on IDs to account for date collisions. |
| @@ -2005,12 +2014,18 @@ function get_adjacent_post( $in_same_term = false, $excluded_terms = '', $previo | |||
| * @since 4.4.0 Added the `$post` parameter. | |||
| * @since 4.9.0 Added the `$order` parameter. | |||
| * @since 6.9.0 Adds ID sort to ensure deterministic ordering for posts with identical dates. | |||
Copilot
AI
Jan 20, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The @SInCE 6.9.0 note in the docblock states "Adds ID sort to ensure deterministic ordering" which is now conditional on whether the filter modifies the clause. This documentation should be updated or removed since it no longer accurately describes the behavior in 6.9.1 where the ID sort is only applied if filters don't modify the SORT clause.
| * @since 6.9.0 Adds ID sort to ensure deterministic ordering for posts with identical dates. | |
| * @since 6.9.0 Introduced ID sort for posts with identical dates. |
| * @since 4.4.0 Added the `$post` parameter. | ||
| * @since 4.9.0 Added the `$order` parameter. | ||
| * @since 6.9.0 Adds ID sort to ensure deterministic ordering for posts with identical dates. | ||
| * @since 6.9.1 Remove deterministic fallback for sites modifying the SORT clause via a filter. See #64390. |
Copilot
AI
Jan 20, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The @SInCE 6.9.1 note mentions "Remove deterministic fallback for sites modifying the SORT clause" but should be more specific. It should clarify that the deterministic sort is still applied by default, but NOT applied when a filter modifies the SORT clause. Consider rewording to: "Conditionally applies deterministic fallback - skips it when filters modify the SORT clause".
| * @since 6.9.1 Remove deterministic fallback for sites modifying the SORT clause via a filter. See #64390. | |
| * @since 6.9.1 Conditionally applies deterministic fallback - skips it when filters modify the SORT clause. See #64390. |
Follow up to #10394
Tests out an idea suggested in https://core.trac.wordpress.org/ticket/64390#comment:10 Props @azaozz
Note
This is mainly to discuss whether it's worth the change, if so good, if not, I can close.
Description
This PR is a follow-up to #10394 that makes the deterministic ordering changes more defensive and plugin-friendly. It ensures that when plugins modify the
get_{$adjacent}_post_whereorget_{$adjacent}_post_sortfilters, the deterministic logic is not applied on top of their modifications.Problem
In PR #10394, deterministic ID-based ordering was added to fix adjacent post navigation for posts with identical dates. However, the implementation applied the deterministic logic before the filters ran, which meant:
Solution
This PR implements a defensive approach that:
Implementation:
$where === $where_prepared(filter didn't modify it)$sort === $sort_prepared(filter didn't modify it)Test Steps
Automated Tests
Run the PHPUnit tests:
Manual Testing
1. Verify Default Behavior (No Filters)
Create test scenario:
post_datevalues (bulk publish drafts)Expected Results:
2. Verify Filter Modifications Are Respected
Test WHERE Filter:
functions.phpor a test plugin:AND p.IDin WHERE clause)Test SORT Filter:
3. Verify Unmodified Filters Still Get Deterministic Logic
Trac ticket: https://core.trac.wordpress.org/ticket/64390