WordPress.org

Make WordPress Core

Opened 7 years ago

Closed 7 years ago

#28159 closed defect (bug) (fixed)

get_body_class makes a raw, uncacheable query for child posts

Reported by: rmccue Owned by: SergeyBiryukov
Milestone: 4.0 Priority: normal
Severity: normal Version: 2.8
Component: Themes Keywords: has-patch commit
Focuses: template Cc:

Description

get_body_class() calls $wpdb->get_var( $wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE post_parent = %d AND post_type = 'page' AND post_status = 'publish' LIMIT 1", $page_id) ) just so it can add a single class.

It also accesses the database directly this way, and is hence not cacheable at all, causing a query to be made on every page for something that's not always needed (but can't be disabled).

Attachments (2)

28159.diff (701 bytes) - added by obenland 7 years ago.
28159.2.diff (622 bytes) - added by SergeyBiryukov 7 years ago.

Download all attachments as: .zip

Change History (9)

@obenland
7 years ago

#1 @obenland
7 years ago

  • Focuses template added
  • Keywords has-patch added
  • Milestone changed from Awaiting Review to 4.0
  • Version set to 2.8

Is 28159.diff what we're looking for?

Before:

SELECT ID FROM wp_posts WHERE post_parent = 2 AND post_type = 'page' AND post_status = 'publish' LIMIT 1

After:

SELECT wp_posts.ID FROM wp_posts WHERE 1=1 AND wp_posts.post_parent = 2 AND wp_posts.post_type = 'page' AND ((wp_posts.post_status = 'publish')) ORDER BY wp_posts.post_date DESC LIMIT 0, 1

Introduced in r11053.

#2 @kovshenin
7 years ago

Using get_posts() will actually make it ~ 5x slower and doesn't really do any useful caching.

#3 follow-up: @nacin
7 years ago

This would work, and would leverage post caches:

$parent_page = get_post( $page_id );
if ( 'page' === $parent_page->post_type && 'publish' === $parent_page->post_status ) {

}

#4 in reply to: ↑ 3 @kovshenin
7 years ago

Replying to nacin: Sure, but that doesn't really give us the page's children. Perhaps "caching" the query result in a _wp_has_children meta and flushing it in wp_insert_post() could work?

#5 follow-up: @SergeyBiryukov
7 years ago

  • Keywords commit added

How about get_pages()? It does use caching: tags/3.9.1/src/wp-includes/post.php#L4162.

#6 in reply to: ↑ 5 @kovshenin
7 years ago

Replying to SergeyBiryukov: looks reasonable.

#7 @SergeyBiryukov
7 years ago

  • Owner set to SergeyBiryukov
  • Resolution set to fixed
  • Status changed from new to closed

In 28696:

Use get_pages() instead of a raw SQL query in get_body_class().

fixes #28159.

Note: See TracTickets for help on using tickets.