Repository navigation
Abilities API: Replace the author_slug filter of core/content-query with an author object - #14673
jorgefilipecosta wants to merge 5 commits into
Conversation
…s no user. The `core/content-query` ability rejected an `author_slug` filter that names no user as an invalid filter, and looked the slug up against the users the current user may see, with a rule of its own. The other filters, such as `ids` and `slugs`, give the empty result when nothing matches their value. Treat `author_slug` the same way, to fix possible inconsistencies: a slug that names no user now matches no post, like a user without posts the current user may read, and the lookup of visible users is removed. A value that is not a string is still rejected. Follow-up to [64388]. See #66268.
…y` with an `author` object. The `core/content-query` ability filtered posts by author through a `where.author_slug` string, while each post returns its author as an `author` object with `id`, `name`, and `slug`. The REST API posts collection filters by author ID, which the ability did not take. Replace the filter with a `where.author` object that takes the `id` or the `slug` the `author` field returns, so a result's author can be given back as a filter. An ID needs no user lookup. When both are given they must name the same user. An ID or slug that names no user matches no post, as before for a slug. A value that is not an object with an ID or a slug, an ID that is not a positive integer, and a slug that is not a string are rejected as invalid filters. Follow-up to [64388]. See #66268.
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. 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. Props Bot commandsYou can trigger Props Bot actions by commenting on this PR:
|
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. |
…`core/content-query`. Say in the schema that an ID and a slug naming different users match no post, mention the filter in the output `author.id` description, and ask for a non-empty slug in the error message. Cover an empty-string `author`, a whole float ID, and which problem an author filter with several reports. Follow-up to [64388]. See #66268.
…` filter of `core/content-query`. Follow-up to [64388]. See #66268.
gziolo
left a comment
There was a problem hiding this comment.
Thank you, Jorge! The author object uses the same keys as the author field in the output, so the input and output now fit together well. Approving.
Before this is committed, please look at the two inline comments. They are about the same thing: the id filter also matches posts of a deleted user, but the schema description and a code comment say it matches no post. The behavior is good, only the text needs a fix, plus one test to keep the behavior.
| /* | ||
| * An author filter that names no user matches no post, like IDs and slugs that name | ||
| * no post, rather than failing the query. An `id` that names no user needs no lookup: | ||
| * the query matches no post on its own. | ||
| */ |
There was a problem hiding this comment.
This comment is not correct for IDs. WP_Query matches the author ID saved on the post (the post_author column). It does not check if the user exists. If a user is deleted, their posts can keep the old ID, and { id: <old ID> } still returns them.
I think this is good behavior. The output still returns author.id for these posts, so the caller can use it as a filter. Let's only fix the comment:
| /* | |
| * An author filter that names no user matches no post, like IDs and slugs that name | |
| * no post, rather than failing the query. An `id` that names no user needs no lookup: | |
| * the query matches no post on its own. | |
| */ | |
| /* | |
| * A slug that names no user, or an ID and a slug that name different users, match no | |
| * post, like IDs and slugs that name no post, rather than failing the query. An `id` is | |
| * not looked up: the query matches the stored author ID, so the posts of a deleted user | |
| * still match it. | |
| */ |
Could you also add a test? Create a post with post_author => REST_TESTS_IMPOSSIBLY_HIGH_NUMBER (like in test_author_object_describes_the_author()), then check that { id: REST_TESTS_IMPOSSIBLY_HIGH_NUMBER } returns it.
There was a problem hiding this comment.
Hi @gziolo, thank you. The suggestion was applied, and test_author_filter_by_id_matches_the_posts_of_a_deleted_user() now checks that { id: REST_TESTS_IMPOSSIBLY_HIGH_NUMBER } returns the post with that stored author ID.
| 'description' => __( "The author's user slug (nicename), as `author.slug` is returned and as the REST API users endpoint returns it in `slug`." ), | ||
| ), | ||
| ), | ||
| 'description' => __( 'Filter by the post author, given as the `id` or the `slug` the `author` field of a post returns. An ID or slug that names no user, or an ID and a slug that name different users, match no post. Only supported for post types that support authors.' ), |
There was a problem hiding this comment.
Same problem as above, but this text is part of the public schema. Agents and MCP clients read it, so it should match the real behavior.
| 'description' => __( 'Filter by the post author, given as the `id` or the `slug` the `author` field of a post returns. An ID or slug that names no user, or an ID and a slug that name different users, match no post. Only supported for post types that support authors.' ), | |
| 'description' => __( 'Filter by the post author, given as the `id` or the `slug` the `author` field of a post returns. An `id` matches the author ID stored on the post, even when that user no longer exists. A `slug` that names no user, or an `id` and a `slug` that name different users, match no post. Only supported for post types that support authors.' ), |
Please also update the 'ID' case in data_author_filters_that_name_no_user(). It passes only because no post has that ID. The new test above covers IDs better, so this case can go.
There was a problem hiding this comment.
Hi @gziolo, thank you. The suggestion was applied, and the ID case was dropped: the test now covers the slug only, as test_author_filter_with_a_slug_that_names_no_user_matches_no_post().
…query` matches the stored author ID. The ID is not looked up, so the posts of a deleted user still match it. Say so in the schema description and the code comment, test it, and keep the empty-result test for slugs only. Follow-up to [64388]. See #66268.
…y` with an `author` object. The `core/content-query` ability filtered posts by author through a `where.author_slug` string, while each post returns its author as an `author` object with `id`, `name`, and `slug`. The REST API posts collection filters by author ID, which the ability did not take. Replace the filter with a `where.author` object that takes the `id` or the `slug` the `author` field returns, so a result's author can be given back as a filter. Developed in #14673. Follow-up to [64388]. Props jorgefilipecosta, gziolo. See #66268. git-svn-id: https://develop.svn.wordpress.org/trunk@64680 602fd350-edb4-49c9-b593-d223f7449a82
…y` with an `author` object. The `core/content-query` ability filtered posts by author through a `where.author_slug` string, while each post returns its author as an `author` object with `id`, `name`, and `slug`. The REST API posts collection filters by author ID, which the ability did not take. Replace the filter with a `where.author` object that takes the `id` or the `slug` the `author` field returns, so a result's author can be given back as a filter. Developed in WordPress/wordpress-develop#14673. Follow-up to [64388]. Props jorgefilipecosta, gziolo. See #66268. Built from https://develop.svn.wordpress.org/trunk@64680 git-svn-id: http://core.svn.wordpress.org/trunk@63830 1a063a9b-81f0-0310-95a4-ce76da25c4cd
|
Committed at e29e51d. |
Follow up to https://core.trac.wordpress.org/changeset/64388. Builds on #14643, whose commit is included here until it lands.
What
where.author_slugfilter ofcore/content-queryis replaced by awhere.authorobject with the optional propertiesidandslug, the keys theauthorfield of a post returns.idmatches the author ID stored on the post, without looking the user up, so the posts of a deleted user are still found by theauthor.idtheir output returns. Aslugthat names no user gives the empty result, as before, and so do anidand aslugthat name different users.idor aslug, anidthat is not a positive integer, and aslugthat is not a non-empty string are rejected as invalid filters, withwhere[author],where[author][id]andwhere[author][slug]as the parameter.Why
author: { id, name, slug }, so a caller can now pass that object back as the filter instead of translating it to a differently named string. @gziolo asked for this shape in Abilities API: Return the empty result for anauthor_slugthat names no user #14643 (comment).How
authoras an object withadditionalProperties: false,minProperties: 1,id(integer, minimum 1) andslug(string, minLength 1), in the positionauthor_slughad.idthrough the existing integer parsing (0 fails closed, sinceWP_Queryreadsauthor => 0as no author filter), thensluglooked up as given. The query argument stays a singleauthoruser ID.author_slugnow nameauthor.author_slugtests are converted, with data providers for the invalid shapes, IDs and slugs, the ID-and-slug combinations, filtering by ID, and the schema shape.Example input, filtering the posts by their author's slug:
{ "where": { "type": "post", "author": { "slug": "cq_author" } }, "fields": [ "id", "title", "author" ] }The same author can be given by ID,
"author": { "id": 3 }, or by both,"author": { "id": 3, "slug": "cq_author" }. The run endpoint takes the input as query arguments:Example output:
{ "items": [ { "id": 7, "title": { "raw": "Ann published", "rendered": "Ann published" }, "author": { "id": 3, "name": "Ann Author", "slug": "cq_author" } } ], "pagination": { "total": 1, "total_pages": 1 } }A slug that names no user,
"author": { "slug": "nobody-here" }, or an ID and a slug naming different users, gives the empty result:{ "items": [], "pagination": { "total": 0, "total_pages": 0 } }The change was drafted with AI assistance and reviewed by me.
Trac ticket: https://core.trac.wordpress.org/ticket/66268
Testing
Verify unit tests are passing: