From 4cdf05f6bc62f0718d3b8da36fdd7daaaefdaaaf Mon Sep 17 00:00:00 2001 From: Boone Gorges Date: Tue, 5 May 2015 19:37:53 +0000 Subject: [PATCH] Improve performance of `get_page_children()`. The new algorithm uses a hash table rather than function recursion, reducing complexity to O(N). On large numbers of pages, the performance improvement is several orders of magnitude. Props santagada, hailin, mihai. Fixes #10852. Built from https://develop.svn.wordpress.org/trunk@32355 git-svn-id: http://core.svn.wordpress.org/trunk@32326 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- wp-includes/post.php | 35 ++++++++++++++++++++++++----------- wp-includes/version.php | 2 +- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/wp-includes/post.php b/wp-includes/post.php index 4d1c61a768..3716cbae72 100644 --- a/wp-includes/post.php +++ b/wp-includes/post.php @@ -4317,25 +4317,38 @@ function get_page_by_title( $page_title, $output = OBJECT, $post_type = 'page' ) } /** - * Retrieve child pages from list of pages matching page ID. + * Identify descendants of a given page ID in a list of page objects. * - * Matches against the pages parameter against the page ID. Also matches all - * children for the same to retrieve all children of a page. Does not make any - * SQL queries to get the children. + * Descendants are identified from the `$pages` array passed to the function. No database queries are performed. * * @since 1.5.1 * - * @param int $page_id Page ID. - * @param array $pages List of pages' objects. + * @param int $page_id Page ID. + * @param array $pages List of page objects from which descendants should be identified. * @return array List of page children. */ function get_page_children( $page_id, $pages ) { - $page_list = array(); + // Build a hash of ID -> children. + $children = array(); foreach ( (array) $pages as $page ) { - if ( $page->post_parent == $page_id ) { - $page_list[] = $page; - if ( $children = get_page_children( $page->ID, $pages ) ) { - $page_list = array_merge( $page_list, $children ); + $children[ intval( $page->post_parent ) ][] = $page; + } + + $page_list = array(); + + // Start the search by looking at immediate children. + if ( isset( $children[ $page_id ] ) ) { + // Always start at the end of the stack in order to preserve original `$pages` order. + $to_look = array_reverse( $children[ $page_id ] ); + + while ( $to_look ) { + $p = array_pop( $to_look ); + $page_list[] = $p; + if ( isset( $children[ $p->ID ] ) ) { + foreach ( array_reverse( $children[ $p->ID ] ) as $child ) { + // Append to the `$to_look` stack to descend the tree. + $to_look[] = $child; + } } } } diff --git a/wp-includes/version.php b/wp-includes/version.php index 357cb8f207..c8831440cb 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -4,7 +4,7 @@ * * @global string $wp_version */ -$wp_version = '4.3-alpha-32354'; +$wp_version = '4.3-alpha-32355'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.