-
Notifications
You must be signed in to change notification settings - Fork 2.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add logic to sort posts by hierarchy #8014
base: trunk
Are you sure you want to change the base?
Add logic to sort posts by hierarchy #8014
Conversation
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the Core Committers: Use this line as a base for the props when committing in SVN:
To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
Test using WordPress PlaygroundThe changes in this pull request can previewed and tested using a WordPress Playground instance. WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser. Some things to be aware of
For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation. |
2cdb0df
to
096976a
Compare
219a01b
to
48a1d59
Compare
c102ffa
to
a6000fc
Compare
@@ -402,6 +409,14 @@ static function ( $format ) { | |||
// Force the post_type argument, since it's not a user input variable. | |||
$args['post_type'] = $this->post_type; | |||
|
|||
if ( Hierarchical_Sort::is_eligible( $request ) ) { | |||
$result = Hierarchical_Sort::run( $args ); | |||
$this->levels = $result['levels']; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@oandregal: Correct me if I'm wrong, but this is the same problem that we had with static variables in the original Gutenberg PR. The concept of posts controller doesn't map 1:1 to the concept of a query, and so attaching the state of a query (levels
) to a controller instance that can outlive it ($this
) seems dangerous.
$new_args = array_merge( | ||
$args, | ||
array( | ||
'fields' => 'id=>parent', | ||
'posts_per_page' => -1, | ||
) | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Modifying the query args with these params look similar to what is happening in the current WP Admin when hierarchical post types are queried without any order. See:
wordpress-develop/src/wp-admin/includes/post.php
Lines 1294 to 1300 in 9ad162e
if ( is_post_type_hierarchical( $post_type ) && empty( $orderby ) ) { | |
$query['orderby'] = 'menu_order title'; | |
$query['order'] = 'asc'; | |
$query['posts_per_page'] = -1; | |
$query['posts_per_archive_page'] = -1; | |
$query['fields'] = 'id=>parent'; | |
} |
I suspect we might need to update the is_eligible()
method with the same check for an empty orderby
query. I also wonder if we need to continue supporting the menu_order
property as the default sorting for these types of queries?
For sites with a lot of posts, doing a query that returns all posts, e.g. posts_per_page => -1
could be very slow, so there should be a way for this to be disabled.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added some thoughts. This is a good start but I think this PR needs work.
* | ||
* @since 6.8.0 | ||
*/ | ||
class Hierarchical_Sort { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do any of the methods in this class need to be static? Static methods have a number of downside, including performance as static methods are not garbage collected in the same way that other methods are. For this one place where the class is used, we could just create an instance of the class and use public methods.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does this need to be another class? Why can't this be part of the WP_REST_Posts_Controller
class?
$new_args = array_merge( | ||
$args, | ||
array( | ||
'fields' => 'id=>parent', | ||
'posts_per_page' => -1, | ||
) | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1
$ancestor = $parent_id; | ||
while ( 0 !== $ancestor ) { | ||
++$level; | ||
$ancestor = self::get_ancestor( $ancestor ); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we not use get_post_parent
or get_ancestors
); | ||
} | ||
|
||
private static function add_hierarchical_ids( &$ids, &$levels, $level, $to_process, $children ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PHP Docs required
return self::sort( $posts ); | ||
} | ||
|
||
private static function get_ancestor( $post_id ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Php docs required.
return true; | ||
} | ||
|
||
public static function run( $args ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PHPdocs required.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two additional questions I have about this PR after thinking about it:
- Is there a reason this should be implemented as a new request param, rather than extending the existing
orderby
to handle this use case? - Is there a reason why it's important to do the sorting and include the
levels
property in the return value, rather than doing that sorting in the client based on the returned post IDs and parents? Returning a REST response shape solely for the purpose of mapping to the visual display in the UI seems like code smell to me unless that value is necessary for some other purpose.
I'm not married to this implementation, it's just an artifact of having been developed in Gutenberg first. It was backported verbatim from there, where there's no |
|
Levels need to be calculated absolutely (based on all the data) and not just relative to the page that is sent to the browser. Otherwise, we'll end up with the wrong levels. For example, if this was the full dataset, and the size of each page sent to the client was 5 items:
If the client only has access to the items of the page, the 1st batch (items 1 to 5) has all the information it needs to calculate the levels. The second batch only contains items 6 to 10, there's no any information about their ancestors, so it won't be able to calculate them properly. |
Trac ticket https://core.trac.wordpress.org/ticket/62701
See related Gutenberg issues/PRs:
What
This PR expands the post controller to allow returning the data by parent-child relationship (sort by hierarchy).
Why
We want to display data in a hierarchical way in the site editor, similarly to what we do in wp-admin:
How to test
Added a new test suite to test the logic.
Steps to test this manually:
(alternatively, you may want to generate a gutenberg zip from
trunk
, use the normalwordpress-develop
setup and change the gutenberg's PHP code in the plugin directory)npm install && npm run build:dev
.trunk
, create a.wp-env.override.json
with the following contents (core is the local path of this PR's repository, so change accordingly):npm run wp-env start
. Thennpm install && npm run dev
.localhost:8888
, open the wp-admin, and go to "Tools > Import". Import this theme test data file, that comes with hierarchical pages (or create your own set of pages).