[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/abilities/ -> class-wp-abilities-content.php (summary)

Abilities API: WP_Abilities_Content class.

File Size: 1762 lines (67 kb)
Included or required: 1 time
Referenced: 0 times
Includes or requires: 0 files

Defines 40 functions

  register()
  register_content_query()
  check_permission()
  parse_filter_int()
  parse_list_input()
  can_query_statuses()
  can_query_status()
  check_read_permission()
  execute_content_query()
  get_input_object()
  normalize_per_page()
  get_query_total()
  should_prime_post_caches()
  is_field_requested()
  get_author_by_slug()
  get_exposed_post_type()
  get_requested_statuses()
  normalize_statuses()
  normalize_ids()
  normalize_slugs()
  normalize_fields()
  get_post_properties()
  get_field_paths()
  get_fields_input_schema()
  get_content_query_input_schema()
  get_content_output_schema()
  get_content_query_output_schema()
  format_post()
  build_post_fields()
  allow_password_content()
  get_title()
  get_rendered_excerpt()
  get_rendered_content()
  get_post_context()
  set_up_post_context()
  restore_post_context()
  format_date()
  prepare_output()
  invalid_page_number_error()
  invalid_filter_error()

Functions
Functions that are not part of a class:

register()   X-Ref
Registers all content abilities.

Must run on the `wp_abilities_api_init` hook.


register_content_query()   X-Ref
Registers the read-only `core/content-query` ability.


check_permission( $input = array()   X-Ref
Permission callback for the `core/content-query` ability.

The request is only gated as a whole here: it needs a logged-in user, a post type
exposed to abilities, and the capabilities to query the explicitly requested statuses.
It reads no post. {@see self::execute_content_query()} enforces row-level read
permissions, since individual rows are unknown until the query runs.

param: mixed $input Optional. The ability input. Default empty array.
return: bool True if the request may proceed, false otherwise.

parse_filter_int( $value, int $min )   X-Ref
Parses a raw input value into an integer of at least a minimum, or null when invalid.

Accepts the whole numbers that the integer schema accepts: native integers, floats such
as the 2.0 that JSON encoders produce, and integer strings such as "2", "2.0", or "+2".
Only the REST run controller converts input to the schema types, so other callers, such
as the MCP adapter or a direct WP_Ability::execute() call, pass them on unconverted.
Anything else, such as a fraction, is rejected rather than coerced: a malformed ID would
otherwise resolve to another post, and a malformed `parent` filter would be read as 0,
which asks for top-level posts.

param: mixed $value The raw input value.
param: int   $min   The smallest acceptable value.
return: int|null The parsed integer, or null when the value is not an integer >= $min.

parse_list_input( array $input, string $key )   X-Ref
Parses a raw list input into a list of strings.

Like schema validation, it also accepts a scalar or a comma-separated string, and
parses it the same way, with wp_parse_list(). A number, such as a slug sent as 2024,
is read as its string form.

param: array<mixed> $input The ability input, or one of its objects, such as `where`.
param: string       $key   The input key holding the list.
return: list<string> The parsed string values; empty when absent or unparseable.

can_query_statuses( array $where, WP_Post_Type $post_type_object )   X-Ref
Checks whether the current user may query the explicitly requested statuses.

The statuses a query covers by default, see {@see self::normalize_statuses()}, only
hold statuses the current user may query, so they need no check.

param: array<mixed> $where            The `where` filters.
param: WP_Post_Type $post_type_object The post type object.
return: bool True if the requested statuses may be queried.

can_query_status( string $status, WP_Post_Type $post_type_object )   X-Ref
Checks whether the current user may query posts in a status.

Like the REST posts controller, any user may query `publish`, while other statuses, such
as `draft`, require edit access. Any user may also query the other publicly viewable
statuses, and `private`, since the query only covers the private posts the user can
read, see {@see self::execute_content_query()}.

param: string       $status           The post status slug.
param: WP_Post_Type $post_type_object The post type object.
return: bool True if the status may be queried.

check_read_permission( WP_Post $post, array $checked_post_ids = array()   X-Ref
Checks if a post can be read by the current user.

Mirrors the REST posts controller's read permission, while keeping this ability
authenticated-only via {@see self::check_permission()}.

param: WP_Post          $post             Post object.
param: array<int, true> $checked_post_ids Post IDs already checked while walking inherited parents.
return: bool Whether the post can be read.

execute_content_query( $input = array()   X-Ref
Executes the `core/content-query` ability.

{@see WP_Ability::execute()} always runs {@see self::check_permission()} first, which
gates the request as a whole. The query still filters every row by read permission,
because the gate cannot know the rows before the query runs.

param: mixed $input Optional. The ability input. Default empty array.
return: array<string, mixed>|WP_Error A page of posts, or a WP_Error on failure.

get_input_object( array $input, string $key )   X-Ref
Reads an object member of the input, such as `where` or `pagination`.

Accepts what schema validation reads as an object: an array, a `stdClass`, or an
empty string. Only the REST run controller converts input to the schema types, so
callers that bypass it, such as a direct WP_Ability::execute() call, can pass any of them.

param: array<mixed> $input The ability input.
param: string       $key   The member name.
return: array<mixed>|null The member as an array, an empty array when it is omitted,

normalize_per_page( array $pagination, bool $lists_posts )   X-Ref
Normalizes the requested per-page value to the supported bounds.

An explicit `per_page` always wins. Otherwise a request that lists posts by ID or slug
pages to the maximum, as `core/users-query` does for its lists, so a caller loading a
known set of posts receives them in one call rather than silently losing the ones past
the default page size. The input schema caps each list at {@see self::MAX_PER_PAGE},
so every post that `ids` lists fits on the first page. A slug can match several posts,
though, so the matches of `slugs` only continue past the first page when more than
that many posts match.

param: array<mixed> $pagination  The `pagination` input.
param: bool         $lists_posts Whether the query lists `ids` or `slugs`.
return: int The clamped per-page value.

get_query_total( WP_Query $query, array $query_args, int $page )   X-Ref
Returns the query total, recovering it when WP_Query skipped the count.

WP_Query leaves `found_posts` at 0 when a requested page has no rows. Re-run a
minimal unpaged query so the caller can distinguish an out-of-range page from
an empty result set, matching the REST posts controller behavior.

param: WP_Query     $query      The executed query.
param: array<mixed> $query_args The arguments used for the executed query.
param: int          $page       The requested page.
return: int Total matching rows across all pages.

should_prime_post_caches( array $fields )   X-Ref
Checks whether requested fields benefit from page-level cache priming.

A whole object counts as a request for its sub-fields, so `content` primes the
caches as `content.rendered` does.

param: list<string> $fields The requested field paths.
return: bool True when post meta and term caches should be primed.

is_field_requested( string $path, array $fields )   X-Ref
Checks whether a field path is requested.

Matches paths as the REST API's `_fields` parameter does, with rest_is_field_included():
a field such as `title` is requested when it or one of its paths, such as
`title.rendered`, is requested, and a path such as `title.rendered` is requested when it
or its whole field is.

param: string       $path   The field path, such as `title` or `title.rendered`.
param: list<string> $fields The requested field paths.
return: bool Whether the field path is requested.

get_author_by_slug( $slug, WP_Post_Type $post_type_object )   X-Ref
Looks up the user an author slug names.

The slug is the user's nicename, which the REST API users endpoint returns as `slug`. It is
looked up as given, like that endpoint's `slug` filter, so the database collation decides
whether a variant in another case matches. A user the current user may not see is reported
like a missing one. The current user can see themselves, any user of the site when they can
list users, and authors with posts in a publicly viewable post type. A user who can edit
others' posts of the post type can also see any user of the site, since they may make any of
them the author, so for them the lookup does tell whether such an account exists.

On multisite the lookup searches the whole network, so posts by authors who are not
members of the site, such as super admins, can still be filtered. Those users are only
visible as the current user or as authors with posts in a publicly viewable post type, so
the lookup does not tell whether an account exists elsewhere on the network.

param: mixed        $slug             The author slug.
param: WP_Post_Type $post_type_object The post type the author is looked up for.
return: WP_User|null The user, or null when the slug does not name a visible user.

get_exposed_post_type( $post_type )   X-Ref
Returns a post type exposed through the Abilities API.

Deliberately resolved on every call rather than cached: post types can be
unregistered or re-registered with different arguments between the ability
being registered and the ability being used.

param: mixed $post_type The post type name.
return: WP_Post_Type|null The post type object, or null when the post type is not exposed.

get_requested_statuses( array $where )   X-Ref
Returns the statuses the `status` filter explicitly requests.

param: array<mixed> $where The `where` filters.
return: list<string> Sanitized post status slugs; empty when none is requested.

normalize_statuses( array $statuses, WP_Post_Type $post_type_object, bool $lists_posts )   X-Ref
Normalizes the statuses a query covers.

Explicitly requested statuses are queried as given, once the permission callback has
allowed them. Otherwise a query covers `publish`, as in the REST posts controller,
unless it lists `ids` or `slugs`. Such a query names the posts it wants, which may be
drafts or private posts, so it covers every non-internal status that
{@see self::can_query_status()} allows instead. The row-level read checks still
withhold the posts the current user cannot read, such as other users' drafts.

param: list<string> $statuses         The explicitly requested statuses; empty when none is requested.
param: WP_Post_Type $post_type_object The post type object.
param: bool         $lists_posts      Whether the query lists `ids` or `slugs`.
return: list<string> Post status slugs.

normalize_ids( array $where )   X-Ref
Normalizes the post IDs the `ids` filter lists.

Like schema validation, it also accepts a single ID or a comma-separated string. Each
ID is read with {@see self::parse_filter_int()}, and one that is not a whole number of
at least 1, such as a fraction, a negative number, or a float too large to hold its
integer exactly, is dropped rather than coerced, so it can never select another post.
A digit string beyond the integer range saturates to PHP_INT_MAX, as REST sanitization
does, which selects no post either.

param: array<mixed> $where The `where` filters.
return: list<int> Unique post IDs; empty when none is valid.

normalize_slugs( array $where )   X-Ref
Normalizes the post slugs the `slugs` filter lists.

Like schema validation, it also accepts a single slug, even one sent as a number, or a
comma-separated string. Each slug is sanitized with sanitize_title(), as WordPress
sanitizes a post slug when it saves the post, so `Hello-World` matches `hello-world`.
A slug that sanitizes to an empty string, such as `!!!`, is dropped: it names no post,
and querying it would match the posts that have no slug yet, such as drafts.

param: array<mixed> $where The `where` filters.
return: list<string> Unique post slugs; empty when none is valid.

normalize_fields( array $input )   X-Ref
Returns the requested field paths, or a lean default set when none are given.

An empty or absent `fields` value selects a lean set of common read fields.
Otherwise the requested paths are returned. The input schema has already
validated them against the supported set before the ability executes, and
{@see self::build_post_fields()} ignores any other path.

param: array<mixed> $input The ability input.
return: list<string> List of requested field paths.

get_post_properties()   X-Ref
Returns the post field definitions, keyed by field name in output order.

This is the single source of truth for the ability's post fields: the output
schema uses the definitions directly, while the input schema `fields` enum lists
each field, followed by the path of each of its sub-fields, such as `title.rendered`.
Read-context fields are returned for readable posts; the `raw` sub-fields only for
posts the current user can edit.

return: array<string, mixed> Post field definitions.

get_field_paths()   X-Ref
Returns the field paths the `fields` input accepts, in output order.

Each post field is followed by the path of each of its sub-fields, such as `title`,
`title.raw` and `title.rendered`. Requesting a field returns all of its sub-fields
that apply, while a sub-field path returns only that sub-field, as the REST API's
`_fields` parameter does.

return: list<string> The field paths.

get_fields_input_schema()   X-Ref
Builds the schema of the `fields` input, shared by all content abilities.

return: array<string, mixed> The `fields` JSON Schema.

get_content_query_input_schema( array $post_types, array $statuses )   X-Ref
Builds the input schema for the `core/content-query` ability.

The input has three members: `where` selects the posts, `fields` selects the fields
returned for each post, and `pagination` selects the page of results. `where` holds
the post type to query in `type`, and any of the filters `ids`, `slugs`, `status`,
`author_slug`, and `parent`, which all combine. Every object sets
`additionalProperties: false`, so an unknown key, such as a misspelled filter, fails
validation instead of being silently ignored.

param: list<string> $post_types Exposed post type names.
param: list<string> $statuses   Requestable post status slugs.
return: array<string, mixed> The input JSON Schema.

get_content_output_schema()   X-Ref
Builds the output schema of a single post, shared by all content abilities.

Only `id` is required, because it is always returned. The other fields are optional
because the `fields` input lets the caller request any subset, and a field is only
present when its post type supports it.

return: array<string, mixed> The post JSON Schema.

get_content_query_output_schema()   X-Ref
Builds the output schema for the `core/content-query` ability.

Every request returns the same shape: a page of posts in `items`, and the totals
across all pages in `pagination`.

return: array<string, mixed> The output JSON Schema.

format_post( WP_Post $post, array $fields )   X-Ref
Formats a post into the ability output shape.

As the REST posts controller does, the post is set up as the global post while its
fields are built, so filters that rely on loop globals, including title filters, see
the requested post. For an editor of a password-protected post, the cookie-based
password gate is also suspended, so rendered fields resolve to real values instead of
protected-post placeholders. The field projection itself is delegated to
{@see self::build_post_fields()}.

param: WP_Post      $post   The post object.
param: list<string> $fields The requested field paths.
return: array<string, mixed> The formatted post data.

build_post_fields( WP_Post $post, array $fields, bool $can_edit, bool $is_protected )   X-Ref
Builds the requested field projection for a post.

Fields are selected as the REST API's `_fields` parameter selects them, with
{@see self::is_field_requested()}. The `id` is always included, whether or not it
was requested, so every returned post can be identified. This also means a post is
never empty, so it always encodes as a JSON object.

Only the fields that the post type supports and the current user can see are included,
and a field none of whose requested sub-fields remain is left out, so it never encodes
as an empty JSON array. Raw sub-fields are edit-context fields, included only when the
current user can edit the post, whether they were requested on their own or through
their field. Rendered sub-fields are read-context fields and are withheld for
password-protected posts unless the current user can edit the post, mirroring the REST
API behavior.

param: WP_Post      $post         The post object.
param: list<string> $fields       The requested field paths.
param: bool         $can_edit     Whether the current user can edit the post.
param: bool         $is_protected Whether rendered fields must be withheld as password-protected.
return: array<string, mixed> The formatted post data.

allow_password_content( $required, $post )   X-Ref
Filters {@see post_password_required()} to unlock only posts the current user can edit.

Added by {@see self::format_post()} while formatting a password-protected post the
current user can edit, so rendered fields resolve to real values without also unlocking
other protected posts that the content filter may render. Mirrors the REST posts
controller's check_password_required().

param: mixed $required Whether the post currently requires a password.
param: mixed $post     The post being checked; a WP_Post when invoked by the core filter.
return: bool Whether the post still requires a password.

get_title( WP_Post $post )   X-Ref
Returns the post title with the protected/private prefixes stripped.

param: WP_Post $post The post object.
return: string The post title.

get_rendered_excerpt( WP_Post $post )   X-Ref
Returns the post excerpt transformed for display.

Applies the `get_the_excerpt` and `the_excerpt` filter chains, as the REST posts
controller does. {@see self::format_post()} has set the post up as the global post.

param: WP_Post $post The post object.
return: string Rendered post excerpt.

get_rendered_content( WP_Post $post )   X-Ref
Returns post content transformed for display.

Applies `the_content`, as the REST posts controller does. {@see self::format_post()}
has set the post up as the global post.

param: WP_Post $post The post object.
return: string Rendered post content.

get_post_context()   X-Ref
Returns the global post context, so it can be restored after a post is rendered.

return: array<string, mixed> The loop globals, keyed by name, leaving out those that are not set.

set_up_post_context( WP_Post $post )   X-Ref
Sets up the global post context for rendering a post.

Sets the global post and calls setup_postdata(), as the REST posts controller does
before it renders a post, so filters that rely on loop globals render against the
requested post.

param: WP_Post $post The post to render.

restore_post_context( array $previous_context, bool $the_post_fired )   X-Ref
Restores the global post context saved by {@see self::get_post_context()}.

Each loop global gets its previous value back, or is unset again when it was not set.
wp_reset_postdata() alone is not enough: it does nothing when the main query has no
post, which would leave the rendered post's data in the globals. When a post was set
up before, setup_postdata() first runs for it again, as wp_reset_postdata() would, so
callbacks on the `the_post` action can restore their own globals too. The saved values
are put back even when such a callback throws. A global post that was never set up
keeps the loop globals that setup_postdata() gives it. The `the_post` count is reset
only when the ability was the first thing to fire that action and no global post was
set, so rendering a post before the main query does not count as starting the loop.

param: array<string, mixed> $previous_context The loop globals that get_post_context() returned.
param: bool                 $the_post_fired   Whether the `the_post` action had fired before the ability set up the post.

format_date( WP_Post $post, string $field, bool $gmt )   X-Ref
Formats a post date field as an ISO 8601 string, in the site's timezone or in GMT.

In GMT, it reads the stored GMT date, deriving it from the local date when it is
missing (e.g. drafts), mirroring the REST posts controller.

param: WP_Post $post  The post object.
param: string  $field Either 'date' or 'modified'.
param: bool    $gmt   Whether to format the date in GMT instead of the site's timezone.
return: string|null The ISO 8601 date, or null if unavailable.

prepare_output( array $items, int $total, int $total_pages )   X-Ref
Builds the ability output for a page of formatted posts.

param: array<int, array<string, mixed>> $items       The formatted posts on the page.
param: int                              $total       Total number of posts across all pages.
param: int                              $total_pages Total number of pages.
return: array<string, mixed> The ability output.

invalid_page_number_error()   X-Ref
Builds the error for a page past the last page of results.

A page that does not exist is reported as not found rather than as an empty list,
so callers can tell it apart from a request that matches no posts.

return: WP_Error The invalid page number error.

invalid_filter_error( string $param, string $message )   X-Ref
Builds the error for a filter that cannot be honored.

As in the REST API's `rest_invalid_param` errors, the error data maps the filter's
input path to the message under `params`, so callers can tell which filter failed
without parsing the translated message.

param: string $param   The filter's input path, such as `where[ids]`.
param: string $message The error message.
return: WP_Error The invalid filter error.



Generated : Sat Oct 17 08:20:33 2026 Cross-referenced by PHPXref