Skip to content

Abilities API: Replace the author_slug filter of core/content-query with an author object - #14673

Closed
jorgefilipecosta wants to merge 5 commits into
WordPress:trunkfrom
jorgefilipecosta:update/content-query-author-object
Closed

jorgefilipecosta wants to merge 5 commits into
WordPress:trunkfrom
jorgefilipecosta:update/content-query-author-object

Conversation

@jorgefilipecosta

@jorgefilipecosta jorgefilipecosta commented Oct 21, 2026 •

Copy link
Copy Markdown
Member

Follow up to https://core.trac.wordpress.org/changeset/64388. Builds on #14643, whose commit is included here until it lands.

What

  • The where.author_slug filter of core/content-query is replaced by a where.author object with the optional properties id and slug, the keys the author field of a post returns.
  • An id matches the author ID stored on the post, without looking the user up, so the posts of a deleted user are still found by the author.id their output returns. A slug that names no user gives the empty result, as before, and so do an id and a slug that name different users.
  • 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 non-empty string are rejected as invalid filters, with where[author], where[author][id] and where[author][slug] as the parameter.

Why

How

  • The input schema describes author as an object with additionalProperties: false, minProperties: 1, id (integer, minimum 1) and slug (string, minLength 1), in the position author_slug had.
  • The execute callback checks the filter in order: post type support, object shape, id through the existing integer parsing (0 fails closed, since WP_Query reads author => 0 as no author filter), then slug looked up as given. The query argument stays a single author user ID.
  • Descriptions and docblocks that named author_slug now name author.
  • Tests: the existing author_slug tests 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:

wp.apiFetch( {
	path: '/wp-abilities/v1/abilities/core/content-query/run?input[where][type]=post&input[where][author][slug]=cq_author&input[fields][]=id&input[fields][]=title&input[fields][]=author',
} );

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:

npm run test:php -- --filter author

…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.
@github-actions

github-actions Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

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:

Props jorgefilipecosta, gziolo.

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.


Props Bot commands

You can trigger Props Bot actions by commenting on this PR:

  • @propsbot add <username> to give props to a GitHub user. Requires write access.
  • @propsbot remove <username> to leave a user out of the props. Requires write access.
  • @propsbot refresh to refresh this list. Adding the props-bot label works too.

@github-actions

Copy link
Copy Markdown

Test using WordPress Playground

The 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

  • All changes will be lost when closing a tab with a Playground instance.
  • All changes will be lost when refreshing the page.
  • A fresh instance is created each time the link below is clicked.
  • Every time this pull request is updated, a new ZIP file containing all changes is created. If changes are not reflected in the Playground instance,
    it's possible that the most recent build failed, or has not completed. Check the list of workflow runs to be sure.

For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation.

Test this pull request with WordPress Playground.

…`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.
Comment thread tests/phpunit/tests/abilities-api/wpRegisterCoreContentAbility.php Outdated
…` filter of `core/content-query`.

Follow-up to [64388]. See #66268.

@gziolo gziolo left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines +620 to +624
/*
* 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.
*/

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:

Suggested change
/*
* 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.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.' ),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
'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.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.
wporg-sync pushed a commit that referenced this pull request Oct 22, 2026
…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
wporg-sync pushed a commit to WordPress/WordPress that referenced this pull request Oct 22, 2026
…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
@jorgefilipecosta

Copy link
Copy Markdown
Member Author

Committed at e29e51d.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants