WP_REST_Posts_Controller

Core class to access posts via the REST API. The most comprehensive controller, serving as the basis for many other content-type controllers.

Class Synopsis

php
class WP_REST_Posts_Controller extends WP_REST_Controller {
    protected $post_type;
    protected $meta;
    protected $password_check_passed = array();
    protected $allow_batch = array( 'v1' => true );
    
    public function __construct( string $post_type );
    public function register_routes();
    
    // Permission Checks
    public function get_items_permissions_check( $request );
    public function get_item_permissions_check( $request );
    public function create_item_permissions_check( $request );
    public function update_item_permissions_check( $request );
    public function delete_item_permissions_check( $request );
    
    // CRUD Operations
    public function get_items( $request );
    public function get_item( $request );
    public function create_item( $request );
    public function update_item( $request );
    public function delete_item( $request );
    
    // Data Preparation
    protected function prepare_item_for_database( $request );
    public function prepare_item_for_response( $item, $request );
    protected function prepare_items_query( $prepared_args, $request );
    
    // Schema & Parameters
    public function get_item_schema();
    public function get_collection_params();
    
    // Permission Helpers
    public function check_read_permission( $post );
    protected function check_update_permission( $post );
    protected function check_create_permission( $post );
    protected function check_delete_permission( $post );
    protected function check_assign_terms_permission( $request );
    
    // Content Handling
    public function can_access_password_content( $post, $request );
    public function check_password_required( $required, $post );
    protected function handle_status_param( $post_status, $post_type );
    protected function handle_featured_media( $featured_media, $post_id );
    protected function handle_terms( $post_id, $request );
    protected function handle_template( $template, $post_id, $validate = false );
    
    // Utilities
    protected function get_post( $id );
    protected function prepare_date_response( $date_gmt, $date = null );
    protected function prepare_links( $post );
    protected function get_available_actions( $post, $request );
    public function check_template( $template, $request );
    public function check_status( $status, $request, $param );
    public function sanitize_post_statuses( $statuses, $request, $parameter );
}

Endpoints

MethodEndpointDescription
GET/wp/v2/postsList posts
POST/wp/v2/postsCreate a post
GET/wp/v2/posts/{id}Get a single post
POST/PUT/PATCH/wp/v2/posts/{id}Update a post
DELETE/wp/v2/posts/{id}Delete a post

Constructor

php
public function __construct( string $post_type )

Parameters:

  • $post_type – The post type slug

Behavior:

  • Sets $this->post_type to the provided type
  • Gets the post type object for rest_base and rest_namespace
  • Creates WP_REST_Post_Meta_Fields instance for meta handling

Collection Parameters

ParameterTypeDefaultDescription
contextstring‘view’Scope under which request is made
pageinteger1Current page
per_pageinteger10Items per page (max 100)
searchstringSearch string
afterdate-timePosts published after date
beforedate-timePosts published before date
modified_afterdate-timePosts modified after date
modified_beforedate-timePosts modified before date
authorarray[]Limit to specific authors
author_excludearray[]Exclude specific authors
excludearray[]Exclude specific IDs
includearray[]Include specific IDs
offsetintegerOffset for pagination
orderstring‘desc’Sort order (asc/desc)
orderbystring‘date’Sort field
search_columnsarray[]Columns to search
slugarrayFilter by slugs
statusarray‘publish’Filter by status
stickybooleanFilter sticky posts (post type only)
categoriesarrayFilter by categories
categories_excludearrayExclude categories
tagsarrayFilter by tags
tags_excludearrayExclude tags

Orderby Options

  • author – Author ID
  • date – Publish date
  • id – Post ID
  • include – Order by include parameter
  • modified – Modified date
  • parent – Parent ID
  • relevance – Search relevance (requires search)
  • slug – Post slug
  • include_slugs – Order by slug include
  • title – Post title
  • menu_order – Menu order (pages/page-attributes)

Schema Properties

The schema varies based on post type support. Core properties:

PropertyTypeContextDescription
idintegerview, edit, embedPost ID (readonly)
datestring/nullview, edit, embedPublish date (site timezone)
date_gmtstring/nullview, editPublish date (GMT)
guidobjectview, editGlobal unique identifier (readonly)
linkstringview, edit, embedPost URL (readonly)
modifiedstringview, editModified date (readonly)
modified_gmtstringview, editModified date GMT (readonly)
slugstringview, edit, embedPost slug
statusstringview, editPost status
typestringview, edit, embedPost type (readonly)
passwordstringeditPost password

Conditional Properties (based on post_type_supports)

PropertySupportTypeDescription
title‘title’objectPost title (raw/rendered)
content‘editor’objectPost content (raw/rendered/protected/block_version)
author‘author’integerAuthor user ID
excerpt‘excerpt’objectPost excerpt (raw/rendered/protected)
featured_media‘thumbnail’integerFeatured image ID
comment_status‘comments’stringComments open/closed
ping_status‘comments’stringPingbacks open/closed
menu_order‘page-attributes’integerMenu order
format‘post-formats’stringPost format
meta‘custom-fields’objectPost meta
sticky(post type only)booleanIs sticky
templatestringPage template
parent(hierarchical)integerParent post ID
categories(taxonomy)arrayCategory term IDs
tags(taxonomy)arrayTag term IDs

Permission Checks

get_items_permissions_check()

  • Returns true for public requests
  • Requires edit_posts capability for edit context

get_item_permissions_check()

  • Verifies post exists and matches controller’s post type
  • Checks password if provided
  • Requires edit_post capability for edit context
  • Calls check_read_permission() for view context

create_item_permissions_check()

  • Requires create_posts capability
  • Checks edit_others_posts for setting different author
  • Checks edit_others_posts or publish_posts for sticky
  • Validates term assignment permissions

update_item_permissions_check()

  • Requires edit_post capability
  • Additional checks for author, sticky, and terms

delete_item_permissions_check()

  • Requires delete_post capability

Key Methods

get_post()

php
protected function get_post( int $id ): WP_Post|WP_Error

Gets the post if ID is valid and matches the controller’s post type.

check_read_permission()

php
public function check_read_permission( WP_Post $post ): bool

Checks if a post can be read. Handles:

  • Published posts (always readable)
  • Private posts (requires read_post capability)
  • Inherited status (checks parent)
  • Public post statuses

prepare_item_for_database()

Maps request parameters to post object properties:

  • titlepost_title
  • contentpost_content
  • excerptpost_excerpt
  • statuspost_status
  • date/date_gmtpost_date/post_date_gmt
  • slugpost_name
  • authorpost_author
  • passwordpost_password
  • parentpost_parent
  • menu_ordermenu_order
  • comment_statuscomment_status
  • ping_statusping_status

prepare_item_for_response()

Prepares full post response including:

  • All schema fields based on context
  • Taxonomy terms
  • Meta fields
  • Links (self, collection, author, replies, revisions, etc.)

handle_terms()

php
protected function handle_terms( int $post_id, WP_REST_Request $request ): null|WP_Error

Updates post terms from request data using wp_set_object_terms().

php
protected function handle_featured_media( int $featured_media, int $post_id ): bool|WP_Error

Sets or removes the post thumbnail.

handle_template()

php
public function handle_template( string $template, int $post_id, bool $validate = false )

Sets the page template via _wp_page_template meta.

The controller adds HAL-style links:

RelationDescription
selfLink to this post
collectionLink to posts collection
aboutLink to post type
authorLink to author (embeddable)
repliesLink to comments (embeddable)
version-historyLink to revisions
predecessor-versionLink to latest revision
upLink to parent (hierarchical)
wp:featuredmediaLink to featured image (embeddable)
wp:attachmentLink to attachments
wp:termLinks to taxonomy terms (embeddable)

Edit context includes action links indicating user capabilities:

ActionDescription
wp:action-publishCan publish posts
wp:action-unfiltered-htmlCan use unfiltered HTML
wp:action-stickyCan make posts sticky
wp:action-assign-authorCan change author
wp:action-create-{taxonomy}Can create terms
wp:action-assign-{taxonomy}Can assign terms

Usage Example

php
// Get posts with specific parameters
$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
$request->set_param( 'per_page', 5 );
$request->set_param( 'categories', array( 1, 2 ) );
$request->set_param( 'orderby', 'title' );
$request->set_param( 'order', 'asc' );

$controller = new WP_REST_Posts_Controller( 'post' );
$response = $controller->get_items( $request );

// Create a post
$request = new WP_REST_Request( 'POST', '/wp/v2/posts' );
$request->set_param( 'title', 'My New Post' );
$request->set_param( 'content', 'Post content here.' );
$request->set_param( 'status', 'publish' );
$request->set_param( 'categories', array( 1 ) );

$response = $controller->create_item( $request );

Extending for Custom Post Types

php
// Register custom post type with REST support
register_post_type( 'book', array(
    'public'       => true,
    'show_in_rest' => true,
    'rest_base'    => 'books',
    'supports'     => array( 'title', 'editor', 'author', 'thumbnail', 'custom-fields' ),
));

// Endpoint automatically available at /wp/v2/books

Source

wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php

Since

WordPress 4.7.0

Changelog

VersionDescription
4.7.0Introduced
5.0.0Added rest_after_insert_{$post_type} action
5.4.0Added tax_relation parameter
5.6.0Added check_status() method
5.7.0Added modified_after and modified_before parameters
5.7.1Added password check bypass for REST requests
5.9.0Added batching support