From bc9f76bd6d698cbd59fb652614bb4b5397a142c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Maneiro?= <583546+oandregal@users.noreply.github.com> Date: Thu, 28 Nov 2024 18:27:50 +0100 Subject: [PATCH] Return posts sorted by hierarchy --- ...ss-gutenberg-rest-posts-controller-6-8.php | 108 ++++++++++++++++++ lib/load.php | 1 + .../src/components/post-list/index.js | 1 + phpunit/build-post-ids-to-display-test.php | 81 +++++++++++++ 4 files changed, 191 insertions(+) create mode 100644 lib/compat/wordpress-6.8/class-gutenberg-rest-posts-controller-6-8.php create mode 100644 phpunit/build-post-ids-to-display-test.php diff --git a/lib/compat/wordpress-6.8/class-gutenberg-rest-posts-controller-6-8.php b/lib/compat/wordpress-6.8/class-gutenberg-rest-posts-controller-6-8.php new file mode 100644 index 00000000000000..8d654f72525642 --- /dev/null +++ b/lib/compat/wordpress-6.8/class-gutenberg-rest-posts-controller-6-8.php @@ -0,0 +1,108 @@ + 'Sort pages by hierarchy.', + 'type' => 'boolean', + 'default' => false, + ); + return $params; +} ); + +add_filter( 'rest_page_query', function ( $args, $request ) { + if ( $request['orderby_hierarchy'] ) { + // Build the list of post ids to be displayed. + $new_args = array_merge( $args, array( + 'fields' => 'id=>parent', + 'posts_per_page' => -1, + ) ); + $query = new WP_Query( $new_args ); + $posts = $query->posts; + $post_ids = sort_ids_by_hierarchy( $posts, $args ); + + // Reconfigure the args to display only the ids in the list. + $args['paged'] = 1; + $args['post__in'] = $post_ids; + } + return $args; +}, 10, 2 ); + +/** + * Sort the post ids by hierarchy. + * + * @param array $posts The posts to sort. + * @param array $args The arguments to sort the posts by. + * @return array The sorted post ids. + */ +function sort_ids_by_hierarchy( $posts, $args = array() ) { + /** + * $posts is: + * [ + * ['ID' => 2, 'post_parent' => 0], + * ['ID' => 3, 'post_parent' => 2], + * ['ID' => 4, 'post_parent' => 2], + * ] + * + * $args is: + * [ + * 'posts_per_page' => 20, + * 'paged' => 1, + * ] + */ + if ( isset( $args['posts_per_page'] ) && $args['posts_per_page'] === 0 ) { + return array(); + } + + $per_page = isset( $args['posts_per_page'] ) && is_int( $args['posts_per_page'] ) ? $args['posts_per_page'] : -1; + $page = isset( $args['paged'] ) && is_int( $args['paged'] ) ? $args['paged'] : 1; + $start = 0; + $end = count( $posts ); + if ( $per_page > 0 ) { + $start = ( $page - 1 ) * $per_page; + $end = $start + $per_page; + } + + /* + * Arrange pages in two arrays: + * + * - $top_level: posts whose parent is 0 + * - $parent_children: post ID as the key and an array of children post IDs as the value. + * Example: parent_children[10][] contains all sub-pages whose parent is 10. + * + */ + + $top_level = array(); + $parent_children = array(); + foreach ( $posts as $post ) { + if ( $post->post_parent === 0 ) { + $top_level[] = $post->ID; + } else { + $parent_children[ $post->post_parent ][] = $post->ID; + } + } + + $ids = array(); + $count = 0; + add_hierarchical_ids( $ids, $top_level, $count, $start, $end, $parent_children ); + + return $ids; +} + +function add_hierarchical_ids( &$ids, $to_process, &$count, $start, $end, $parent_children ) { + foreach ( $to_process as $id ) { + if ( $count >= $start && $count < $end ) { + $ids[] = $id; + } + $count++; + + if ( isset( $parent_children[ $id ] ) ) { + add_hierarchical_ids( $ids, $parent_children[ $id ], $count, $start, $end, $parent_children ); + } + } +} diff --git a/lib/load.php b/lib/load.php index 26af78f3173c53..d499600d550a56 100644 --- a/lib/load.php +++ b/lib/load.php @@ -45,6 +45,7 @@ function gutenberg_is_experiment_enabled( $name ) { require __DIR__ . '/compat/wordpress-6.8/block-comments.php'; require __DIR__ . '/compat/wordpress-6.8/class-gutenberg-rest-comment-controller-6-8.php'; require __DIR__ . '/compat/wordpress-6.8/class-gutenberg-rest-post-types-controller-6-8.php'; + require __DIR__ . '/compat/wordpress-6.8/class-gutenberg-rest-posts-controller-6-8.php'; require __DIR__ . '/compat/wordpress-6.8/rest-api.php'; // Plugin specific code. diff --git a/packages/edit-site/src/components/post-list/index.js b/packages/edit-site/src/components/post-list/index.js index 200aa60ee17977..1193d3ded42bab 100644 --- a/packages/edit-site/src/components/post-list/index.js +++ b/packages/edit-site/src/components/post-list/index.js @@ -290,6 +290,7 @@ export default function PostList( { postType } ) { _embed: 'author', order: view.sort?.direction, orderby: view.sort?.field, + orderby_hierarchy: true, search: view.search, ...filters, }; diff --git a/phpunit/build-post-ids-to-display-test.php b/phpunit/build-post-ids-to-display-test.php new file mode 100644 index 00000000000000..16588a6e27977a --- /dev/null +++ b/phpunit/build-post-ids-to-display-test.php @@ -0,0 +1,81 @@ + 11, + 'post_parent' => 9, + ), + array( + 'ID' => 2, + 'post_parent' => 0, + ), + array( + 'ID' => 8, + 'post_parent' => 0, + ), + array( + 'ID' => 3, + 'post_parent' => 2, + ), + array( + 'ID' => 5, + 'post_parent' => 3, + ), + array( + 'ID' => 7, + 'post_parent' => 4, + ), + array( + 'ID' => 9, + 'post_parent' => 8, + ), + array( + 'ID' => 4, + 'post_parent' => 2, + ), + array( + 'ID' => 6, + 'post_parent' => 3, + ), + array( + 'ID' => 10, + 'post_parent' => 8, + ), + ); + + public function test_return_all_post_ids() { + $output = sort_ids_by_hierarchy( $this->input ); + $this->assertEquals( array( 2, 3, 5, 6, 4, 7, 8, 9, 11, 10 ), $output ); + } + + public function test_return_first_page() { + $output = sort_ids_by_hierarchy( $this->input, array( + 'posts_per_page' => 3, + 'paged' => 1, + ) ); + $this->assertEquals( array( 2, 3, 5 ), $output ); + } +}