diff --git a/README.md b/README.md index 7760bf5b4..8aa6c4f16 100644 --- a/README.md +++ b/README.md @@ -3150,7 +3150,7 @@ wp post get [--field=] [--fields=] [--format=] Gets a list of posts. ~~~ -wp post list [--=] [--field=] [--fields=] [--format=] +wp post list [--=] [--p=|ID] [--title=|post_title] [--name=<slug>|post_name] [--author=<author>|post_author] [--author_name=<author_name>] [--post_type=<post_type>] [--post_status=<post_status>] [--post_parent=<post_parent>] [--post_mime_type=<post_mime_type>] [--menu_order=<menu_order>] [--comment_status=<comment_status>] [--ping_status=<ping_status>] [--comment_count=<comment_count>] [--s=<string>] [--year=<year>] [--monthnum=<monthnum>] [--day=<day>] [--m=<yearmonth>] [--w=<week>] [--field=<field>] [--fields=<fields>] [--format=<format>] ~~~ Display posts based on all arguments supported by [WP_Query()](https://developer.wordpress.org/reference/classes/wp_query/). @@ -3159,7 +3159,77 @@ Only shows post types marked as post by default. **OPTIONS** [--<field>=<value>] - One or more args to pass to WP_Query. + One or more args to pass to WP_Query. The arguments below are the ones + that filter on what this command displays; anything else WP_Query accepts + still works and is documented with WP_Query itself. + + [--p=<id>|ID] + Filter by post ID. `--ID` is the name of the column this filters and is + accepted as an alias. + + [--title=<title>|post_title] + Filter by post title, matched in full. `--post_title` is the name of the + column this filters and is accepted as an alias. + + [--name=<slug>|post_name] + Filter by post slug. `--post_name` is the name of the column this filters + and is accepted as an alias. + Note: this makes the query a single-post one, and WP_Query returns a draft + from one of those only to a user who can edit it. WP-CLI runs as no user + unless the global `--user` argument says otherwise, so pass that to filter + drafts by slug. + + [--author=<author>|post_author] + Filter by the ID of the post's author. `--post_author` is the name of the + column this filters and is accepted as an alias. + + [--author_name=<author_name>] + Filter by the 'user_nicename' of the post's author. + + [--post_type=<post_type>] + Filter by post type. Defaults to 'post'. Accepts a comma-separated list, + or 'any' for every type registered without 'exclude_from_search'. + + [--post_status=<post_status>] + Filter by post status. Defaults to 'any', which is every status + registered without 'exclude_from_search' - so trashed and auto-draft posts + are left out until asked for by name, e.g. `--post_status=trash`. + + [--post_parent=<post_parent>] + Filter by the ID of the parent post. + + [--post_mime_type=<post_mime_type>] + Filter by MIME type. Only attachments carry one. + + [--menu_order=<menu_order>] + Filter by menu order. + + [--comment_status=<comment_status>] + Filter by comment status. Accepts 'open' or 'closed'. + + [--ping_status=<ping_status>] + Filter by ping status. Accepts 'open' or 'closed'. + + [--comment_count=<comment_count>] + Filter by number of comments. + + [--s=<string>] + Only list the posts matching this search term. + + [--year=<year>] + Filter by four-digit year, e.g. 2024. + + [--monthnum=<monthnum>] + Filter by month number, 1 to 12. + + [--day=<day>] + Filter by day of the month, 1 to 31. + + [--m=<yearmonth>] + Filter by year and month together, e.g. 202401. + + [--w=<week>] + Filter by week of the year, 0 to 53. [--field=<field>] Prints the value of a single field for each post. diff --git a/features/post.feature b/features/post.feature index 02a845e01..7d7571e1b 100644 --- a/features/post.feature +++ b/features/post.feature @@ -591,3 +591,100 @@ Feature: Manage WordPress posts """ {"block_version":1} """ + + Scenario: Filtering by the wp_posts column names + When I run `wp post create --post_title='Alpha' --post_status=publish --porcelain` + Then STDOUT should be a number + + # 'title', 'name' and 'author' are WP_Query's names for these filters. The + # columns they filter on are spelled differently, and passing the column + # name used to reach WP_Query as an argument it does not know: it was + # dropped, and every post came back. They are aliases now. + When I run `wp post list --title='Hello world!' --format=count` + Then STDOUT should be: + """ + 1 + """ + + When I run `wp post list --post_title='Hello world!' --format=count` + Then STDOUT should be: + """ + 1 + """ + + When I run `wp post list --name=alpha --format=count` + Then STDOUT should be: + """ + 1 + """ + + When I run `wp post list --post_name=alpha --format=count` + Then STDOUT should be: + """ + 1 + """ + + # Only the bundled post matches: a post created by WP-CLI has author 0, + # because WP-CLI runs as no user unless told otherwise. + When I run `wp post list --author=1 --format=count` + Then STDOUT should be: + """ + 1 + """ + + When I run `wp post list --post_author=1 --format=count` + Then STDOUT should be: + """ + 1 + """ + + When I run `wp post list --p=1 --format=count` + Then STDOUT should be: + """ + 1 + """ + + When I run `wp post list --ID=1 --format=count` + Then STDOUT should be: + """ + 1 + """ + + Scenario: Filtering drafts by slug needs a user + When I run `wp post create --post_title='Beta' --post_name=beta --post_status=draft --porcelain` + Then STDOUT should be a number + + # '--name' makes this a single-post query, and WP_Query hands a draft from + # one of those only to a user who can edit it. WP-CLI is no user by default. + When I run `wp post list --name=beta --field=ID` + Then STDOUT should be empty + + # The global '--user' argument is what makes it reachable. + When I run `wp post list --name=beta --user=1 --field=ID` + Then STDOUT should not be empty + + Scenario: Trashed posts need their status named + When I run `wp post create --post_title='Doomed' --post_status=publish --porcelain` + Then STDOUT should be a number + And save STDOUT as {DOOMED_ID} + + When I run `wp post delete {DOOMED_ID}` + Then STDOUT should contain: + """ + Success: Trashed post + """ + + # This command defaults post_status to 'any', and WP_Query reads 'any' as + # every status registered without 'exclude_from_search' - which leaves out + # 'trash' and 'auto-draft'. + When I run `wp post list --field=ID` + Then STDOUT should not contain: + """ + {DOOMED_ID} + """ + + When I run `wp post list --post_status=trash --field=ID` + Then STDOUT should contain: + """ + {DOOMED_ID} + """ diff --git a/src/Post_Command.php b/src/Post_Command.php index fd472fbea..ab3a26f79 100644 --- a/src/Post_Command.php +++ b/src/Post_Command.php @@ -617,7 +617,77 @@ protected function delete_callback( $post_id, $assoc_args ) { * ## OPTIONS * * [--<field>=<value>] - * : One or more args to pass to WP_Query. + * : One or more args to pass to WP_Query. The arguments below are the ones + * that filter on what this command displays; anything else WP_Query accepts + * still works and is documented with WP_Query itself. + * + * [--p=<id>|ID] + * : Filter by post ID. `--ID` is the name of the column this filters and is + * accepted as an alias. + * + * [--title=<title>|post_title] + * : Filter by post title, matched in full. `--post_title` is the name of the + * column this filters and is accepted as an alias. + * + * [--name=<slug>|post_name] + * : Filter by post slug. `--post_name` is the name of the column this filters + * and is accepted as an alias. + * Note: this makes the query a single-post one, and WP_Query returns a draft + * from one of those only to a user who can edit it. WP-CLI runs as no user + * unless the global `--user` argument says otherwise, so pass that to filter + * drafts by slug. + * + * [--author=<author>|post_author] + * : Filter by the ID of the post's author. `--post_author` is the name of the + * column this filters and is accepted as an alias. + * + * [--author_name=<author_name>] + * : Filter by the 'user_nicename' of the post's author. + * + * [--post_type=<post_type>] + * : Filter by post type. Defaults to 'post'. Accepts a comma-separated list, + * or 'any' for every type registered without 'exclude_from_search'. + * + * [--post_status=<post_status>] + * : Filter by post status. Defaults to 'any', which is every status + * registered without 'exclude_from_search' - so trashed and auto-draft posts + * are left out until asked for by name, e.g. `--post_status=trash`. + * + * [--post_parent=<post_parent>] + * : Filter by the ID of the parent post. + * + * [--post_mime_type=<post_mime_type>] + * : Filter by MIME type. Only attachments carry one. + * + * [--menu_order=<menu_order>] + * : Filter by menu order. + * + * [--comment_status=<comment_status>] + * : Filter by comment status. Accepts 'open' or 'closed'. + * + * [--ping_status=<ping_status>] + * : Filter by ping status. Accepts 'open' or 'closed'. + * + * [--comment_count=<comment_count>] + * : Filter by number of comments. + * + * [--s=<string>] + * : Only list the posts matching this search term. + * + * [--year=<year>] + * : Filter by four-digit year, e.g. 2024. + * + * [--monthnum=<monthnum>] + * : Filter by month number, 1 to 12. + * + * [--day=<day>] + * : Filter by day of the month, 1 to 31. + * + * [--m=<yearmonth>] + * : Filter by year and month together, e.g. 202401. + * + * [--w=<week>] + * : Filter by week of the year, 0 to 53. * * [--field=<field>] * : Prints the value of a single field for each post.