Make WordPress Core

Opened 3 years ago

Last modified 5 weeks ago

#59354 new defect (bug)

Unnecessary queries performed when updating a post without providing categories or tags

Reported by: johnbillion's profile johnbillion Owned by:
Milestone: Awaiting Review Priority: normal
Severity: normal Version:
Component: Posts, Post Types Keywords: has-patch has-unit-tests
Focuses: performance Cc:

Description

Given an existing post with at least some categories or tags present, updating the post via wp_update_post() (which calls wp_insert_post()) with data that does not include categories or tags, many unnecessary taxonomy-related database queries are performed. This slows down the saving significantly.

  • If $postarr doesn't contain a post_category element, there's no point in calling wp_set_post_categories().
  • If $postarr doesn't contain a tags_input element, there's no point in calling wp_set_post_tags()

Todo

  • Need tests to verify the above is correct
  • Need a list of queries that are performed before and after the change

To reproduce

  1. Publish a post with at least one category
  2. Update the post via:
    <?php
    wp_insert_post( [
      'ID' => $id,
      'post_content' => 'Hello, World!',
    ] );
    
  3. Observe that a significant number of unnecessary taxonomy queries are performed

Attachments (1)

59354.diff (2.1 KB) - added by motylanogha 2 months ago.
Patch for current trunk. Skips wp_set_post_categories() on update when post_category is not in $postarr, matching the existing tags_input guard. Includes unit test verifying fewer queries. All 62 wp_insert_post tests pass.

Download all attachments as: .zip

Change History (4)

This ticket was mentioned in PR #6807 on WordPress/wordpress-develop by @LeonidasMilossis.


2 years ago
#1

  • Keywords has-patch has-unit-tests added; needs-patch needs-unit-tests removed

#2 @LeonidasMilossis
2 years ago

If $postarr doesn't contain a tags_input element, there's no point in calling wp_set_post_tags().

We already do that in wp_insert_post() and indeed there's no extra queries unless we add 'tags_input' => $tag_id, in the wp_insert_post() params.

So, that part can probably be removed from the scope of this ticket.

The submitted PR adds a unit test that attests to that.

@motylanogha
2 months ago

Patch for current trunk. Skips wp_set_post_categories() on update when post_category is not in $postarr, matching the existing tags_input guard. Includes unit test verifying fewer queries. All 62 wp_insert_post tests pass.

This ticket was mentioned in PR #11698 on WordPress/wordpress-develop by @motylanogha.


5 weeks ago
#3

wp_insert_post() always called wp_set_post_categories() on update, even when the caller did not pass post_category. The fallback then re-set the post's existing category list, which still goes through term-cache invalidation, term-relationship lookups, and counted toward the per-request query budget — a measurable regression for callers like REST API updates that change a single field.

This PR gates that call on either (a) it being a new post or (b) post_category being explicitly set in the args. The tags_input and tax_input paths were already correctly guarded.

Tests cover:

  • set_object_terms does not fire for the category taxonomy on a parameterless update
  • Existing categories survive a parameterless update (regression guard)
Note: See TracTickets for help on using tickets.