Make WordPress Core

Opened 7 weeks ago

Last modified 38 hours ago

#64455 new enhancement

WordPress Core Abilities

Reported by: jorgefilipecosta's profile jorgefilipecosta Owned by:
Milestone: 7.0 Priority: normal
Severity: normal Version:
Component: AI Keywords: has-patch
Focuses: Cc:

Description

Quoted from https://github.com/WordPress/ai/issues/40. As the Abilities API is developed for inclusion in WordPress Core, we need to define a default set of abilities that will be bundled with it. This proposal outlines a foundational set of abilities intended to be safe, useful for the majority of use cases, and non-destructive by default.

All ability names below follow the established namespace/ability-name convention enforced by the API. The core namespace is used to designate that they are part of the WordPress Core set.

Proposed Core Abilities

Site and Settings - core/get-site-info - core/get-settings - core/update-settings

Users - core/get-current-user - core/get-user - core/find-users - core/update-user-profile

Posts and Pages - core/find-posts - core/get-post - core/create-post - core/update-post - core/find-pages - core/get-page - core/create-page - core/update-page

Media - core/find-media-items - core/get-media-item - core/upload-media-item - core/update-media-item

Comments - core/find-comments - core/get-comment

Taxonomy - core/find-categories - core/get-category - core/find-tags - core/get-tag

Menus - core/get-menu-locations - core/get-menu

Themes - core/get-active-theme - core/list-themes

Plugins - core/list-plugins - core/get-plugin - core/activate-plugin - core/deactivate-plugin - core/update-plugin

Out of Scope for this Proposal

  • Deleting content, users, or media.
  • Installing or uninstalling plugins and themes.
  • Theme switching.
  • Creating or modifying menus.
  • Any actions that cannot be easily reversed.

Open Questions

# Plugin Management: This proposal includes abilities to activate, deactivate, and update plugins. Given the potential for site instability, what guardrails are essential? Should these actions be limited to an allowlist of specific plugins by default to prevent unintended changes?
# Destructive Actions: This initial set deliberately excludes destructive actions like deleting posts or users. Should a future version include them? If so, what additional security measures, like a ‘trash’ or ‘undo’ ability, would be required to maintain a high degree of safety?

Change History (11)

This ticket was mentioned in PR #10665 on WordPress/wordpress-develop by @jorgefilipecosta.


7 weeks ago
#1

  • Keywords has-patch added

Part of: https://github.com/WordPress/ai/issues/40 cc: @Jameswlepage
Equivalent core PR of: https://github.com/WordPress/gutenberg/pull/74234 (in Gutenberg).
Inspired by the work on https://github.com/galatanovidiu/mcp-adapter-implementation-example/tree/experiment/layerd-mcp-tools/includes/Abilities by @galatanovidiu.

Ticket: https://core.trac.wordpress.org/ticket/64455

## Core abilities organization

This PR also proposes a logic for how core abilities are organized. In abilities.php, we have two functions: wp_register_core_abilities and wp_register_ability_category (or in the case of Gutenberg, _gutenberg_register_core_abilities and _gutenberg_register_core_ability_categories). These functions then call ability registration functions that are inside the abilities folder. If the ability is simple, it can be registered in just a single internal function, e.g., _wp_register_site_info_ability; for complex abilities, we can register them in a class (like this post management one).

The abilities can be in both Gutenberg and core. Having them in Gutenberg allows us to use them in the workflows functionality that is being worked on by @senadir and allows us to get some testing before core is released.

Gutenberg unregisters the equivalent core ones, so Gutenberg is the source of truth. The same ability can exist in Gutenberg and core, but Gutenberg takes precedence so we can test changes in Gutenberg before releasing in core (similar to what happens with blocks and other WordPress artifacts).

## Core Post management abilities

This PR adds core post management abilities for the WordPress abilities API: core/create-post, core/get-post, core/find-posts, and core/update-post.

It supports nested query support for meta_query, tax_query, and date_query matching WordPress's native WP_Query structure with AND/OR relations. This allows very complex query operations which the REST API does not allow and may be useful for agents to find information.

It uses the permission callback mechanism and tries to correctly check permissions for all cases. The basic permission checking logic first checks the basic and common use case (user can edit, create, or see a post), then we go into specifics in separate functions that are reused for checking status changes (e.g., publish), author changes, and taxonomy assignment permissions.

The class WP_Posts_Abilities_Gutenberg is organized into 6 main areas:

  • Ability Registration: The main part that does the wp_register_ability calls.
  • Initialization: Initializes shared data between the abilities, e.g., schemas.
  • Output Formatting: Formats the post object (and taxonomies) for output shared between all abilities.
  • Permission Checking: Permission checking logic; some parts are also shared between abilities.
  • Query Processing: Utilities to process queries and map the ability input format to the WP_Query format.
  • Data Processing: Utilities to process input data, sanitize it, map to other formats, etc.

## Missing

The idea of this PR is mainly to get feedback if this is the right direction for the post management abilities. There are some things that are missing:

  • Automated testing: Deeply covering all the abilities. If we agree with this approach, I will add the tests to this PR.
  • Partial Edits: Not all edits are possible, e.g., it is not possible to mark a post as sticky. We need to decide if marking a post as sticky should be done on the update/create post abilities, following the REST API approach, or if we should have a specific ability for that, following the wp_core PHP API approach where we have the wp_update_post function and also stick_post/unstick_post functions. We can decide on what to do regarding the missing edits as follow-ups, as the PR is already too big.
  • Pagination: Pagination was not yet implemented; we need to have a general solution for pagination at the abilities API level.

## Test plan

  • Open /wp-admin/edit.php?post_type=post.
  • Open the browser console and paste the following code to load the abilities API:
const abilitiesAPI = (await import( '@wordpress/abilities' ) );
  • [ ] Verify core/create-post creates posts with various fields (title, content, status, meta, taxonomies):
await abilitiesAPI.executeAbility('core/create-post', {post_type: 'post', title: 'Hello World', content: 'My awesome content', 'status': 'publish', meta: {a:23, c:1} } );
  • [ ] Verify core/get-post retrieves posts by ID with optional taxonomy/meta inclusion:
await abilitiesAPI.executeAbility('core/get-post', {id: 334, include_meta: true, include_taxonomies: true} )
  • [ ] Verify core/find-posts queries work with nested meta_query, tax_query, and date_query.
  • Create posts with the following structure where the title a-23|c-1 represents a post with meta key "a" value of 23 and meta key "c" value of 1. Also adds the correct tags.

https://github.com/user-attachments/assets/a5e8f456-1739-41f2-81ee-040c6c02b527

  • Execute complex find post queries like:
await abilitiesAPI.executeAbility('core/find-posts', {

    post_type: 'post',

    include_meta: true,

    meta_query: {

        queries: [

            {

                key: 'footnotes',

                compare: 'EXISTS',

            },  

        ]

    }

});

await abilitiesAPI.executeAbility('core/find-posts', {

    post_type: 'post',

    include_meta: true,

    meta_query: {

        relation: 'AND',

        queries: [

            {

                key: 'a',

                compare: '=',

                value: '23'

            },

            {

                relation: 'OR',

                queries: [

            {

                key: 'b',

                compare: '=',

                value: '1'

            }, {

                key: 'c',

                compare: '=',

                value: '1'

            } ] }

                

        ]

    }

});

await abilitiesAPI.executeAbility('core/find-posts', {

    post_type: 'post',

    include_meta: true,

    tax_query: {

        relation: 'AND',

        queries: [

            {

                taxonomy: 'post_tag',

                field: 'slug',

                terms: ['t-23']

            },

            {

                relation: 'OR',

                queries: [

                    {

                        taxonomy: 'post_tag',

                        field: 'slug',

                        terms: ['c-1']

                    },

                    {

                        taxonomy: 'post_tag',

                        field: 'slug',

                        terms: ['b-1']

                    }

                ]

            }

        ]

    }

});



await abilitiesAPI.executeAbility('core/find-posts', {

    post_type: 'post',

    date_query: {

        relation: 'AND',

        queries: [

            { year: 2025 },

            {

                relation: 'OR',

                queries: [

                    { day: 26 },

                    { month: 11 }

                ]

            }

        ]

    }

});
  • [ ] Verify core/update-post modifies existing posts correctly:
await abilitiesAPI.executeAbility('core/update-post', {
    id: 327,
    content: 'Hello'
});
  • [ ] Test permission checks prevent unauthorized access, e.g., users without publish permissions trying to change status to published, etc.

@jason_the_adams commented on PR #10665:


4 weeks ago
#2

I'm not entirely confident in my thought here, but it is one I've wrestled with so I'll share it here open-handedly. 😄

I go back and forth on the idea of polymorphic abilities like this. That is, should the create-post ability be able to create _any_ post? Or strictly the post post type? In which case there'd be other abilities such as create-page, create-attachment, and so forth.

On the one hand, this is consistent with how the underlying functions work. But do we simply want to surface low-level functions like that to abilities? Are Abilities low level in the same way and are merely another form of function? I'm inclined to say no, my reason being that Abilities are designed to be multi-contextual — direct execution, REST, Command Palette, MCP, AI function declarations, etc. As input and output parameters get more complex, adapting them to these various contexts gets harder. Some contexts handles certain complexity well, while others get tricky fast.

Having more specific Abilities also means we can take things like pinning, page templates, attachment sizes, and so forth, and include them as part of the input/output parameters. If we go generic, then we're back to addressing things as meta, which is not as discoverable, not as easy to work with, more fragile, and so forth.

Now, one could then wonder about how Abilities work with custom post types, especially those that work very similarly to posts. If there are specific Abilities, then how do those get their own Abilities without folks having to always put in effort to make them? I propose updating register_post_type to have an $args['register_ability'] parameter which can be:

  • true
  • false
  • array( 'create' => true/false, 'read' => true/false, 'update' => true/false, 'delete' => true/false

This would use the slug to optionally create create-$slug, get-$slug and so forth Abilities. If the custom post type is more complicated and wants to add it's own Abilities, it can opt-out and do so with no problem.

Curious what others think! The more I see Abilities used, especially multi-contextually, the more convinced I am that simpler and more focused is better than complexities such as polymorphism.

@jorgefilipecosta commented on PR #10665:


4 weeks ago
#3

Thank you a lot for sharing you thoughts @JasonTheAdams.
I'm also not certain if we should have a single set of abilities to manage all post types or abilities per post type, with a mechanism to automatically generate them.

My idea was that both approaches would be complementary we would have a raw building block that supports managing any kind of post. And then specific post types needing more flexibility could register their own abilities which internally may even call or reuse parts of the core one.

I think we may also give it a try to the abilities per post type approach (with functionality to automatically generate abilities for a post type) so we can compare both live. The downside I see with that is that we have more abilities, e.g: in a site with 10 simples CPT's using the default management abilities we may easily have 10*4 =40 post management abilities vs just 4 generic ones, which may pollute a little bit the context on LLM agents but if we have good search and filtering abilities that may be acceptable.

@jason_the_adams commented on PR #10665:


4 weeks ago
#4

My idea was that both approaches would be complementary we would have a raw building block that supports managing any kind of post.

I think this words for every other post type, but what about the post post type with its unique properties like being sticky? It ends up being the most generic? Or it has two sets of Abilities?

The downside I see with that is that we have more abilities, e.g: in a site with 10 simples CPT's using the default management abilities we may easily have 10*4 =40 post management abilities vs just 4 generic ones, which may pollute a little bit the context on LLM agents but if we have good search and filtering abilities that may be acceptable.

You're not wrong, and that's the challenge of Abilities trying to be multi-contextual. That said, for things like MCP we're going to have an extraordinary amount of tools anyway, which is why categories were introduced as a way of laying tools into progressive exposure. Once discovered, though, simpler tools will be easier for the LLM to navigate. They do not do great with complex input parameters. I'm also nervous how successfully the LLMs would use meta.

@justlevine commented on PR #10665:


4 weeks ago
#5

The downside I see with that is that we have more abilities, e.g: in a site with 10 simples CPT's using the default management abilities we may easily have 10*4 =40 post management abilities vs just 4 generic ones, which may pollute a little bit the context on LLM agents but if we have good search and filtering abilities that may be acceptable.

You're not wrong, and that's the challenge of Abilities trying to be multi-contextual.

Highlighting and stressing this point. We urgently need to stop conflating Abilities (a primitive ) with LLM tools (an abstraction) or worse MCP (a _failed_ abstraction). It also happens to be that recent patterns regarding progressive disclosure and search layers do a very good job at addressing current-gen issues with MCP tools mucking up the context window. That's not to argue that we shouldn't care about the number of abilities, just underscoring why it's so bad to keep conflating them when we're trying to work on WordPress core.

Necessary caveats out of the way, I'd recommend we solve the naming issue holistically with nested namespaces, a pattern that because it's good for human cognitive overload, which _just so happens_ to mean that it aligns with inference best practices too. (related: https://core.trac.wordpress.org/ticket/64345#comment:5).

Which would turn these into:

  • core/posts/find _or_ get (As noted inline, I think getting a single post is superfluous, and both use cases can be more intuitively handled with an improved input shape, e.g. by ).
  • core/posts/create
  • core/posts/update

(Yes it makes the Ability Category redundant. That's a flaw with Ability Categories not this).

---

Sharing some broader design thoughts, since as noted this PR is partially investigative:

But do we simply want to surface low-level functions like that to abilities? Are Abilities low level in the same way and are merely another form of function? I'm inclined to say no, my reason being that Abilities are designed to be multi-contextual — direct execution, REST, Command Palette, MCP, AI function declarations, etc. As input and output parameters get more complex, adapting them to these various contexts gets harder. Some contexts handles certain complexity well, while others get tricky fast.

As designed, they are intended to be primitives: reliably stabilized groupings of functionality that demarcate exactly where intended public consumption ends and "implementation detail" begins. Because the input/output schemas are enforced, consumers can reliably ignore whatever is going on inside the ability and rely on the ability shape. For the same reason, developers can more reliably play around inside the ability without worrying about downstream effects on the ecosystem; they can still break their own functionality, but the "integration" remains stable.

So what functionality deserves to be fenced into an ability? Integration "touchpoints" aka the shared flows that folks are likely to consume in multiple contexts. (Kinda like how public/private methods provide some guarantees on a class-level, but from an integrative perspective instead of declarative). What doesn't need to be an ability? Flows that don't need those guarantees.

For plugins, a pretty easy way to delineate them is as integration user stories: How can external integrations relying on my code "do something". Find {any number of } posts, create { any number of } events, buy {a varying list of} products.
Next step would be asking is that something we want other software to be "able" to do. Then we get into "API Design" and try to overlay and understand the shared use cases so we can come up with an acceptable and stable "boundary" so our schema can act as the separation of concerns we need.

For _core_, the considerations are IMO a bit different: since we're (ostensibly) backwards compatible, we're not usually too worried about breaking things (IOW the programmatic public/private class methods and our "meant for external integration" distinctions align).

Instead, it's about what existing reusable shared flowed can we abstract out to our other use cases, and want other abilities and flows to be able to consumed (in most if not all cases) statelessly. We want as few absolute number of WP_Abilitys needed to cover as many distinct "verbs" and common denominators between the different consumption contexts as possible.
(We can also use them to provide predictability and type safety to parts of WordPress that for "backward compatibility" reasons require a lot of boilerplate to be reliable. Settings ability as a typesafe, performant, and permission validated alternative get_option() is a perfect example of this #10747 ).

Then, the consumers ("adapters") can inflate/deflate/shape abilities based on their needs.

  • WP_REST expands out to wp/v3/{post_type}/{verb}, and lets you pass a post_types?: string[] to the posts/* endpoint
  • wpcli keeps it as wp posts {verb}, fanning out and filtering some of the flags.
  • Command Palette flips it to {verb} {post_type}`, filtering and autocompleting the different layers of args.
  • graphql exposes the {post_type} to the RootQuery/Mutation using the schema to register the GraphQL Types and arg shapes.
  • MCP renames them to {verb}_action, nests the args into 2-3 frequency groups
  • etc.

Similarly, we'll get the most mileage using ?array<T> instead of separate paths for single/multiple inputs/outputs, nesting to create input/output shapes instead of giving everything the same hierarchy, and using consistent (to each other), semantic namings/groupings for our args - and more broadly our abilities - instead of trying to mimic the underlying WordPress core functions that we or any implementers can already use directly.

@jason_the_adams commented on PR #10665:


3 weeks ago
#6

Hey @justlevine! 👋

We urgently need to stop conflating Abilities (a primitive ) with LLM tools (an abstraction) or worse MCP (a _failed_ abstraction).

To be clear, I don't think the point here (or at least mine) necessarily is specific to LLMs. Where you're quoting me I'm talking about multi-contextualism. A significant intent of Abilities is to be multi-contextual (e.g. AI, Command Palette, REST). Part of what I'm wrestling through as I see more Abilities being created is identifying best practices for Abilities — even one's we'd be willing to document.

I will respectfully add: I don't think it's incorrect to bring up LLM considerations in these contexts. While we shouldn't design this _for_ LLMs, it was a significant part of the inspiration for the Abilities API, and is arguably an important part of the future. So please don't consider this "conflating" and assume the other person's thinking. It's about bringing our thoughts and considerations to the table. 🙂

As I think on things, my inclination is that simple Abilities are more portable than complex ones. The Command Palette is one I think through, where I imagine what this Ability would look like in that context. An Ability that's straightforward with a few clear input parameters will be easier to port than something polymorphic, with complex object input parameters that change significantly, and so forth.

Nested Namespaces
The more you share the more I like this. I've been on the fence, but I like it. Also, I actually like that the Ability Category _can_ be a part of the namespace, but it doesn't have to be. The category is a mechanism meant for helping to drill down into Abilities in a multiple contexts and isn't necessarily meant to be tied to the namespace. If the namespace shares the slug, great.

Then, the consumers ("adapters") can inflate/deflate/shape abilities based on their needs.

Hmm. I'm curious how you imagine these integrations working. If I'm following, you're talking about taking a polymorphic Ability and giving it special treatment within each adaptation? An issue here is that it means each adapter has to handle this Ability specially — as opposed to having a show_in_command_palette type configuration that can be applied to any Ability.

Or am I misunderstanding you? I'm quite open to that possibility. Hahah! 😄

Thanks for your thoughts!

@justlevine commented on PR #10665:


3 weeks ago
#7

To be clear, I don't think the point here (or at least mine) necessarily is specific to LLMs. [...]
I will respectfully add: I don't think it's incorrect to bring up LLM considerations in these contexts. While we shouldn't design this for LLMs, it was a significant part of the inspiration for the Abilities API, and is arguably an important part of the future. So please don't consider this "conflating" and assume the other person's thinking. It's about bringing our thoughts and considerations to the table. 🙂

(Apologies for coming off otherwise, my intention was to yes-and my own separate point, precisely in order to help identify best practices 🙇 ).

I meant "conflating" of literal the literal architectural patterns, not the conversational points. As in Abilities should be usable _by_ MCP (broad abstraction) or _by_ tool/function calls (narrow abstraction), and not necessarily 1:1. That distinction doesn't invalidate considerations or issues, it simply allows us to decouple the _solution_ to the problem of "how many abilities is too many to have in my LLM's context window", similar considerations that would alter an otherwise holistic approach (yada yada the rest of what I wrote).
Other recent examples. https://github.com/WordPress/abilities-api/issues/158 or https://core.trac.wordpress.org/ticket/64483

The Command Palette is one I think through, where I imagine what this Ability would look like in that context. An Ability that's straightforward with a few clear input parameters will be easier to port than something polymorphic, with complex object input parameters that change significantly, and so forth.

Can you share some more on what you're imagining here?
I want to confirm we're both we're picturing the same composable wrapper/adapter pattern, where we're from an engineering POV we're just "abstracting a schema". In which case (still IMO) it's not the polymorphism or even how nested it is that defines the "complexity", but how well designed it is. And to me "simple" is a conceptual scale not programmatic. (E.g. checkout<NestedObjectInput> is simpler and would make a better Ability and abstract out better to e.g CP than get_client_orders_from_last_month<UserID> ).

Then, the consumers ("adapters") can inflate/deflate/shape abilities based on their needs.

[...] An issue here is that it means each adapter has to handle this Ability specially — as opposed to having a show_in_command_palette type configuration that can be applied to any Ability.

Or am I misunderstanding you?

Yeah I think a misunderstanding, I very much agree with the issue you highlighted, and think that the Ability config needs to be the source of truth and whenever possible the adapter (REST, CLI, CP, blah blah ) should be agnostic and whenever possible _blind_ to what's happening underneath, using whatever combination of ability props + metadata needed to (holistically) guide that transition. E.g. at its most basic

/// SomeIntegrationAdapter.php
...
foreach( $abilities as $ability ) {
   //  e.g `RestAdapter::map_input_schema_to_rest_args( $ability->get_input_schema(), $ability_name )`
   // versus `CLI_Adapter::prepare_ability_flags( $the_entire_ability ) etc`. 
   // or `$command_label = $meta['cp']['custom_label'] ?: CP_Adapter::derive_label_from( $meta->annotations )`
   $registration_args = $this->coerce_ability_to_shape( $ability );
   
   register_some_thing( ...$registration_args )
}

@extrachill commented on PR #10665:


3 weeks ago
#8

I really think this might come down to a documentation gap. The fact that I had to speak with a maintainer directly to understand this API, despite it being included in core.

Thinking of it as a primitive and building block has massively improved my code.

We should document more clearly the Abilities API so that people understand it is designed to live at the bottom of the funnel. When you understand that, it really changes the game.

Grouping it with actions + filters is appropriate from my understanding.

I honestly disagree with my own feature request after using the API appropriately.

#9 @peterwilsoncc
3 days ago

  • Priority changed from high to normal
  • Type changed from defect (bug) to enhancement
  • Version trunk deleted

@jorgefilipecosta Are you able to write up a merge proposal for this on the make/core blog? cc @flixos90 @jeffpaul

The pull request mentions:

This PR adds core post management abilities for the WordPress abilities API: core/create-post, core/get-post, core/find-posts, and core/update-post.

It supports nested query support for meta_query, tax_query, and date_query matching WordPress's native WP_Query structure with AND/OR relations. This allows very complex query operations which the REST API does not allow and may be useful for agents to find information.

As the existing REST API endpoints include these abilities, the proposal would need to make clear why the new endpoints are needed instead of a proposal to expand the existing endpoints to allow for using the extended features.

I'd also like to see details on how the performance and security implications of including these features has been evaluated.

#10 @jorgefilipecosta
2 days ago

Hi @peterwilsoncc, thank you for looking into this issue and bringing important discussion points.

@jorgefilipecosta Are you able to write up a merge proposal for this on the make/core blog? cc @flixos90 @jeffpaul

I'm happy to write a post on Make/Core to get wider visibility on this. That said, I wanted to clarify, for future tasks, aren't merge proposals typically intended for larger efforts developed outside of core (e.g., a feature plugin) that need to be merged in? In this case, abilities are being developed incrementally, one by one, via PRs directly against core.

As the existing REST API endpoints include these abilities, the proposal would need to make clear why the new endpoints are needed instead of a proposal to expand the existing endpoints to allow for using the extended features.

On the question of why new abilities rather than expanding the existing REST API endpoints, I believe this is addressed in the "Why WordPress Needed Abilities" section of https://make.wordpress.org/ai/2025/11/21/meet-abilities-wordpress-new-functional-core/. The key point is that the REST API alone was not a sufficiently standardized layer for sharing functionality across different contexts. The Abilities API was introduced precisely so that plugins and core can expose their functionality in a standardized, machine-readable way that can be consumed by CLIs, MCP (via the MCP Adapter), browser-based MCP clients, and more. The REST API is one transport channel for ability consumption, but it's not the only one.

For example, core has already introduced core/get-site-info and core/get-user-info, both of which could technically be done via the REST API, but we still standardized that information as abilities. The same reasoning applies to post management, setting management, etc.
If we accept the premise that the Abilities API is the standardized way for core and plugins to declare what they can do (which we did, given that the Abilities API is already part of core) then it follows that core itself should expose its own base functionality (like creating, reading, and querying posts) as abilities. These are foundational operations, and without them, features like the WP AI Client (https://make.wordpress.org/core/2026/02/03/proposal-for-merging-wp-ai-client-into-wordpress-7-0/), which integrates directly with abilities, wouldn't be able to perform basic, useful tasks like post and setting retrieval/manipulation.

I'd also like to see details on how the performance and security implications of including these features has been evaluated.

Regarding security: the post abilities follow the same pattern established by the existing abilities. Each ability has a permission_callback that checks whether the current user can perform the action using the existing roles and capabilities system. For the specific case of meta_query, tax_query, and date_query, the intent is not to expose new information. A consumer could already use the REST API to retrieve all posts and then filter by meta, taxonomy, or date client-side, it would just be a very inefficient way of doing it. To avoid accidental data leakage, we will rely on the show_in_abilities pattern that was introduced for settings, so only meta keys or taxonomies that explicitly opt in will be queryable; the rest will be filtered out.

Regarding performance: we are not creating new query logic ourselves. The plan is to rely on already existing core functions (like WP_Query, get_post, wp_insert_post, etc.) to retrieve and update the information. Plugins and core are already using these functions extensively, so they should be solid in terms of performance. If a performance issue were to surface, it would likely need to be addressed in those existing functions rather than in the ability layer itself.

#11 @peterwilsoncc
38 hours ago

Replying to jorgefilipecosta:

Regarding security: the post abilities follow the same pattern established by the existing abilities. Each ability has a permission_callback that checks whether the current user can perform the action using the existing roles and capabilities system. For the specific case of meta_query, tax_query, and date_query, the intent is not to expose new information. A consumer could already use the REST API to retrieve all posts and then filter by meta, taxonomy, or date client-side, it would just be a very inefficient way of doing it. To avoid accidental data leakage, we will rely on the show_in_abilities pattern that was introduced for settings, so only meta keys or taxonomies that explicitly opt in will be queryable; the rest will be filtered out.

I'm seeing some big problems with the proposed pull request.

While logged in as a subscriber I was able to:

  • Query non publicly viewable post types, registered with the code
    <?php
    register_post_type( 'pwcc_test_type', [
            'labels' => [
                    'name'          => 'Private Post Types',
                    'singular_name' => 'Private Post Type',
            ],
            'publicly_queryable' => false,
            'show_ui' => true,
            'show_in_rest' => true,
    ] );    
    
  • View unregistered post meta, not visible to the API. (I used _edit_lock which not even admins have access to via the UI)
  • See the raw content form rather than the rendered content form.
Note: See TracTickets for help on using tickets.