Opened 3 hours ago
Last modified 2 hours ago
#66298 new defect (bug)
wp_set_object_terms() leaves term_order at 0 for newly added terms in sorted taxonomies when term counting is deferred
| Reported by: | jdeep | Owned by: | |
|---|---|---|---|
| Priority: | normal | Milestone: | Awaiting Review |
| Component: | Taxonomy | Version: | |
| Severity: | normal | Keywords: | has-patch has-unit-tests |
| Cc: | Focuses: |
Description (last modified by )
For a taxonomy registered with 'sort' => true, wp_set_object_terms() is meant to store terms in the order they are passed. When term counting is deferred and a term is added to an object that already has terms, the new term is left at the column default term_order = 0. It then sorts ahead of the existing terms instead of after them.
The wrong value is written to wp_term_relationships so the order of terms is destroyed.
Steps to reproduce
Add this MU plugin to a site. It registers a sorted taxonomy and defers term counting.
<?php /** * Plugin Name: Term order bug reproduction * Description: Registers a sorted taxonomy and defers term counting, to reproduce the `term_order` bug in `wp_set_object_terms()`. */ add_action( 'init', static function () { register_taxonomy( 'byline', 'post', array( 'label' => 'Byline Author', 'sort' => true, 'args' => array( 'orderby' => 'term_order' ), 'show_in_rest' => true, ) ); wp_defer_term_counting( true ); } );
Then, in wp-admin:
- Go to Posts > Byline Author and create three terms:
Alice,BobandCharlie. - Create a new post.
- From the Quick Edit panel, add
Alice, thenBobto Byline Authors and save the post. - Add
Charliein the same panel, afterBob. Save the post again. - Check the Byline Authors again from the Quick Edit Panel
Result: Chalie, Alice, Bob
Expected: Alice, Bob, Charlie
See Video: https://github.com/user-attachments/assets/9c91783e-ecd6-4201-84de-e99e2bf08819
For sorted taxonomies, wp_set_object_terms() reads the object's terms again before it assigns term_order, and only numbers the terms it finds in that read.
That read is cached. Normally the term count update clears the cache before the read happens. When term counting is deferred, nothing clears it, so the read returns the old list without the newly added term. The new term is skipped and keeps term_order = 0.
wp_set_object_terms() does clear the cache itself, but only after this read. That was added in #40306.
We hit this during a bulk content migration. We turned off term counting for the whole run with wp_defer_term_counting( true ) to improve migration speed. Byline authors were stored in a sorted taxonomy, and on posts with more than one author the byline order came out wrong.
Change History (2)
This ticket was mentioned in PR #14242 on WordPress/wordpress-develop by @jdeep.
3 hours ago
#1
- Keywords has-patch has-unit-tests added
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)
For taxonomies registered with
'sort' => true,wp_set_object_terms()re-reads the object's terms before it assignsterm_order. That read is cached, and when term counting is deferred nothing invalidates the cache after the new relationships are inserted. The newly added term is missing from the read, is skipped, and keepsterm_order = 0.This invalidates the term query cache right after new relationships are added, so the read always includes them. When counting is not deferred, the count update already does this.
Adds two tests: one where the cache is primed by an earlier
wp_get_object_terms()call, and one where the taxonomy'sargsorder byterm_order, which makeswp_set_object_terms()prime the cache itself.Bug Reproduction:
<?php /** * Plugin Name: Term order bug reproduction * Description: Registers a sorted taxonomy and defers term counting, to reproduce the `term_order` bug in `wp_set_object_terms()`. */ add_action( 'init', static function () { register_taxonomy( 'byline', 'post', array( 'label' => 'Byline Author', 'sort' => true, 'args' => array( 'orderby' => 'term_order' ), 'show_in_rest' => true, ) ); wp_defer_term_counting( true ); } );Result:
Chalie, Alice, BobExpected:
Alice, Bob, Charliehttps://github.com/user-attachments/assets/9c91783e-ecd6-4201-84de-e99e2bf08819
AI assistance: Yes
Tool(s): Claude Code
Model(s): Opus 5.5
Used for: Debugging the issue and drafted the patch and unit tests. I reviewed the implementation and the code changes and ran the new tests.