Repository navigation
Abilities: Sync core/content-query with WordPress core - #1208
Conversation
Apply the changes that shipped with the `core/content-query` ability in WordPress core (r64388, Trac #66268): - The input has three members: `where` selects the posts, `fields` the fields returned for each post, and `pagination` the page. - `where` requires the post type in `type`, and filters by `ids`, `slugs`, `status`, `author_slug`, or `parent`. The single-post lookups by `id` and by post type and `slug` are removed. - The output always holds the posts in `items` and the totals in `pagination`. - Fields are nested, such as `title.rendered` and `content.raw`, and a field such as `title` returns all of its sub-fields. - Filters that cannot be honored are rejected instead of dropped, and a page past the last one returns a 404 error. - Only a `show_in_abilities` value of `true` exposes a post type. The polyfill stores any other value as `false`, as core does. - The REST run endpoint tests from core are ported as well.
The `core/read-content` alias can no longer keep the old input and output contract after syncing `core/content-query` with WordPress core, so it is removed. Use `core/content-query` with the new `where`, `fields`, and `pagination` input instead.
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. 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:
|
✅ WordPress Plugin Check Report
📊 ReportAll checks passed! No errors or warnings found. 🤖 Generated by WordPress Plugin Check Action • Learn more about Plugin Check |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## develop #1208 +/- ##
=============================================
+ Coverage 84.41% 84.68% +0.27%
- Complexity 3709 3718 +9
=============================================
Files 149 149
Lines 14139 14239 +100
=============================================
+ Hits 11936 12059 +123
+ Misses 2203 2180 -23
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
WordPress core replaced the `where.author_slug` filter with a `where.author` object in r64680. The object takes the `id` or the `slug` that the `author` field of a post returns. A slug that names no user, or an `id` and a `slug` that name different users, now match no post instead of returning an error. The tests are ported from the updated core test. See WordPress/wordpress-develop@e29e51d.
|
I pushed one more commit to keep up with core r64680. The |
…t-query-with-core
WordPress core now returns the name and slug of a post author only to users who may see that author, in r64688. These users are the author, users who can edit them or list users, and users who can read one of their published posts in a post type exposed to abilities. The `author.slug` filter follows the same rule, so it cannot confirm a user that the `author` field hides. The tests are ported from the updated core test. See WordPress/wordpress-develop@38a613a.
|
I pushed another commit to keep up with core r64688. The author name and slug of a post are now shown only to users who may see that author, and the |
|
@gziolo I did security audit for this PR and also other abilitys PRs that sync the abilities to match up with upcoming core abilities. No high level findings in any of the PRs. The only concern Mythos raised was that all three classes unconditionally unregister the core-provided ability and register their own copy at wp_abilities_api_init priority 11: Once WordPress 7.2 ships these abilities, any 7.2.x security release that patches them will be silently overridden on sites running this plugin until the plugin re-syncs. The same mechanism also means a stale plugin on 7.3+ would pin an older contract. Recommendation: Gate the override on a version check (for example, only override when $wp_version is below the core revision the class was synced from, or when core does not register the ability at all), or at minimum document this in the release notes and keep a tracked "synced from xxx" marker in each class so the sync status is auditable. This is not a vulnerability in the PRs themselves, but it is the most likely way these PRs lead to a real exposure later. |
|
The audit LLM also noticed a small author visibility inconsistency. |
|
Thanks for the audit, @saarnilauri! I confirmed both findings on the latest branch. @jorgefilipecosta, could you please check them too? I will leave both decisions to you.
I'd like to land this PR as is, and sync any core fix to the plugin right after it lands. |
What?
See #66268, r64388, r64680, r64688.
This PR syncs the
core/content-queryability with the version that landed in WordPress core. The plugin acts as a polyfill until WordPress 7.2 is out. It also removes the deprecatedcore/read-contentalias.Why?
The ability was first built in this plugin (#739) and then moved to WordPress core. During the core review, the input and output shape changed a lot. The plugin should behave the same as core, so code written for the plugin keeps working on WordPress 7.2.
The old alias cannot keep the old contract after these changes, so it is removed. This is the same as what #1206 does for
core/read-settingsand #1207 does forcore/read-users.How?
The PR has four main commits:
includes/Abilities/Content/Content.phpis now a copy of the core classWP_Abilities_Content. Each difference from core is marked with a// Plugin:comment: theinit()andregister_category()methods, unregistering the copy from core, an explicitshow_in_rest, and theaitext domain. A fewphpcs:ignoreand@phpstan-ignorecomments are needed for the plugin's stricter rules.core/read-contentis no longer registered.author_slugfilter with anauthorobject. The plugin now does the same.These are breaking changes for callers:
{ where, fields, pagination }.whererequires the post type intype, and takesids,slugs,status,author, andparent.authoris an object with theidor theslugthat theauthorfield of a post returns. The old root-levelid,post_type,slug,include,page, andper_pageare removed.{ items, pagination: { total, total_pages } }. A single post is no longer returned as a bare object.title.renderedinstead oftitle_rendered, andtypeinstead ofpost_type. A field such astitlereturns all of its sub-fields.authorslug that names no user returns no posts.nameandslugarenullunless the current user may see the author. This is the author, users who can edit them or list users, and users who can read one of their published posts. Theauthor.slugfilter follows the same rule.Other changes:
show_in_abilitiespolyfill: as in core, onlytrueexposes a post type. The polyfill now stores any other value asfalse. It still stands down once core declares the flag.ai/get-post-details: the deprecation hint now points tocore/content-querywithwhere.ids.Tests:
ContentTest.phpis ported from the core testwpRegisterCoreContentAbility.php. It also keeps a test that only the plugin needs: the plugin replaces a copy core already registered.Content_RestTest.phpis new. It is ported from the core testwpRestAbilitiesContentController.phpand runs the ability through the REST run endpoint.Use of AI Tools
AI assistance: Yes
Tool(s): Claude Code
Model(s): Claude Opus 5.5
Used for: Comparing the core commit with the plugin, porting the code and tests, updating the e2e specs, and running the checks. I reviewed the diff and the test results.
Testing Instructions
npm run test:php -- --filter Content.npx wp-env --config=.wp-env.test.json run cli --env-cwd=wp-content/plugins/ai bash -c "WP_MULTISITE=1 vendor/bin/phpunit -c phpunit.xml.dist --filter Content".npx wp-env --config=.wp-env.test.json run cli wp plugin activate ai. Then runnpx wp-scripts test-playwright --config tests/e2e/playwright.config.ts tests/e2e/specs/abilities/core-content-query.spec.js tests/e2e/specs/experiments/custom-abilities.spec.js.core/content-querywith{ "where": { "type": "post" }, "fields": [ "id", "title.rendered" ] }and check that the result hasitemsandpagination.Changelog Entry
🤖 Generated with Claude Code