PHPwordpressintermediate

Create Custom WordPress REST API Endpoint

Add custom REST API endpoints to extend WordPress functionality

#wordpress#rest-api#api#endpoints#json
Share this snippet:

Code

php
1// Register custom REST API endpoint
2function register_custom_api_endpoint() {
3 register_rest_route('custom/v1', '/posts', array(
4 'methods' => 'GET',
5 'callback' => 'get_custom_posts',
6 'permission_callback' => '__return_true', // Public endpoint
7 ));
8
9 register_rest_route('custom/v1', '/posts/(?P<id>\d+)', array(
10 'methods' => 'GET',
11 'callback' => 'get_custom_post_by_id',
12 'permission_callback' => '__return_true',
13 'args' => array(
14 'id' => array(
15 'validate_callback' => function($param) {
16 return is_numeric($param);
17 }
18 ),
19 ),
20 ));
21
22 register_rest_route('custom/v1', '/posts', array(
23 'methods' => 'POST',
24 'callback' => 'create_custom_post',
25 'permission_callback' => 'check_admin_permission',
26 ));
27
28 register_rest_route('custom/v1', '/search', array(
29 'methods' => 'GET',
30 'callback' => 'search_content',
31 'permission_callback' => '__return_true',
32 'args' => array(
33 'query' => array(
34 'required' => true,
35 'sanitize_callback' => 'sanitize_text_field',
36 ),
37 ),
38 ));
39}
40add_action('rest_api_init', 'register_custom_api_endpoint');
41
42// Get custom posts
43function get_custom_posts($request) {
44 $args = array(
45 'post_type' => 'post',
46 'posts_per_page' => 10,
47 'post_status' => 'publish',
48 );
49
50 $posts = get_posts($args);
51 $data = array();
52
53 foreach ($posts as $post) {
54 $data[] = array(
55 'id' => $post->ID,
56 'title' => $post->post_title,
57 'content' => apply_filters('the_content', $post->post_content),
58 'excerpt' => $post->post_excerpt,
59 'date' => $post->post_date,
60 'author' => get_the_author_meta('display_name', $post->post_author),
61 'thumbnail' => get_the_post_thumbnail_url($post->ID, 'large'),
62 'categories' => wp_get_post_categories($post->ID, array('fields' => 'names')),
63 'tags' => wp_get_post_tags($post->ID, array('fields' => 'names')),
64 );
65 }
66
67 return new WP_REST_Response($data, 200);
68}
69
70// Get single post by ID
71function get_custom_post_by_id($request) {
72 $post_id = $request['id'];
73 $post = get_post($post_id);
74
75 if (empty($post) || $post->post_status !== 'publish') {
76 return new WP_Error('not_found', 'Post not found', array('status' => 404));
77 }
78
79 $data = array(
80 'id' => $post->ID,
81 'title' => $post->post_title,
82 'content' => apply_filters('the_content', $post->post_content),
83 'excerpt' => $post->post_excerpt,
84 'date' => $post->post_date,
85 'author' => array(
86 'name' => get_the_author_meta('display_name', $post->post_author),
87 'avatar' => get_avatar_url($post->post_author),
88 ),
89 'thumbnail' => get_the_post_thumbnail_url($post->ID, 'large'),
90 'categories' => wp_get_post_categories($post->ID, array('fields' => 'names')),
91 'tags' => wp_get_post_tags($post->ID, array('fields' => 'names')),
92 'meta' => get_post_meta($post->ID),
93 );
94
95 return new WP_REST_Response($data, 200);
96}
97
98// Create new post
99function create_custom_post($request) {
100 $params = $request->get_json_params();
101
102 $post_data = array(
103 'post_title' => sanitize_text_field($params['title']),
104 'post_content' => wp_kses_post($params['content']),
105 'post_status' => 'draft',
106 'post_type' => 'post',
107 );
108
109 $post_id = wp_insert_post($post_data);
110
111 if (is_wp_error($post_id)) {
112 return new WP_Error('creation_failed', 'Failed to create post', array('status' => 500));
113 }
114
115 return new WP_REST_Response(array(
116 'id' => $post_id,
117 'message' => 'Post created successfully',
118 ), 201);
119}
120
121// Search content
122function search_content($request) {
123 $query = $request->get_param('query');
124
125 $args = array(
126 's' => $query,
127 'post_type' => 'post',
128 'posts_per_page' => 20,
129 'post_status' => 'publish',
130 );
131
132 $search_query = new WP_Query($args);
133 $results = array();
134
135 if ($search_query->have_posts()) {
136 while ($search_query->have_posts()) {
137 $search_query->the_post();
138
139 $results[] = array(
140 'id' => get_the_ID(),
141 'title' => get_the_title(),
142 'excerpt' => get_the_excerpt(),
143 'url' => get_permalink(),
144 'thumbnail' => get_the_post_thumbnail_url(get_the_ID(), 'medium'),
145 );
146 }
147 wp_reset_postdata();
148 }
149
150 return new WP_REST_Response($results, 200);
151}
152
153// Permission callback
154function check_admin_permission() {
155 return current_user_can('edit_posts');
156}

Create Custom WordPress REST API Endpoint

Create custom REST API endpoints to expose custom data, handle external requests, or build headless WordPress applications.

// Register custom REST API endpoint
function register_custom_api_endpoint() {
    register_rest_route('custom/v1', '/posts', array(
        'methods'  => 'GET',
        'callback' => 'get_custom_posts',
        'permission_callback' => '__return_true', // Public endpoint
    ));

    register_rest_route('custom/v1', '/posts/(?P<id>\d+)', array(
        'methods'  => 'GET',
        'callback' => 'get_custom_post_by_id',
        'permission_callback' => '__return_true',
        'args' => array(
            'id' => array(
                'validate_callback' => function($param) {
                    return is_numeric($param);
                }
            ),
        ),
    ));

    register_rest_route('custom/v1', '/posts', array(
        'methods'  => 'POST',
        'callback' => 'create_custom_post',
        'permission_callback' => 'check_admin_permission',
    ));

    register_rest_route('custom/v1', '/search', array(
        'methods'  => 'GET',
        'callback' => 'search_content',
        'permission_callback' => '__return_true',
        'args' => array(
            'query' => array(
                'required' => true,
                'sanitize_callback' => 'sanitize_text_field',
            ),
        ),
    ));
}
add_action('rest_api_init', 'register_custom_api_endpoint');

// Get custom posts
function get_custom_posts($request) {
    $args = array(
        'post_type'      => 'post',
        'posts_per_page' => 10,
        'post_status'    => 'publish',
    );

    $posts = get_posts($args);
    $data = array();

    foreach ($posts as $post) {
        $data[] = array(
            'id'           => $post->ID,
            'title'        => $post->post_title,
            'content'      => apply_filters('the_content', $post->post_content),
            'excerpt'      => $post->post_excerpt,
            'date'         => $post->post_date,
            'author'       => get_the_author_meta('display_name', $post->post_author),
            'thumbnail'    => get_the_post_thumbnail_url($post->ID, 'large'),
            'categories'   => wp_get_post_categories($post->ID, array('fields' => 'names')),
            'tags'         => wp_get_post_tags($post->ID, array('fields' => 'names')),
        );
    }

    return new WP_REST_Response($data, 200);
}

// Get single post by ID
function get_custom_post_by_id($request) {
    $post_id = $request['id'];
    $post = get_post($post_id);

    if (empty($post) || $post->post_status !== 'publish') {
        return new WP_Error('not_found', 'Post not found', array('status' => 404));
    }

    $data = array(
        'id'           => $post->ID,
        'title'        => $post->post_title,
        'content'      => apply_filters('the_content', $post->post_content),
        'excerpt'      => $post->post_excerpt,
        'date'         => $post->post_date,
        'author'       => array(
            'name'   => get_the_author_meta('display_name', $post->post_author),
            'avatar' => get_avatar_url($post->post_author),
        ),
        'thumbnail'    => get_the_post_thumbnail_url($post->ID, 'large'),
        'categories'   => wp_get_post_categories($post->ID, array('fields' => 'names')),
        'tags'         => wp_get_post_tags($post->ID, array('fields' => 'names')),
        'meta'         => get_post_meta($post->ID),
    );

    return new WP_REST_Response($data, 200);
}

// Create new post
function create_custom_post($request) {
    $params = $request->get_json_params();

    $post_data = array(
        'post_title'   => sanitize_text_field($params['title']),
        'post_content' => wp_kses_post($params['content']),
        'post_status'  => 'draft',
        'post_type'    => 'post',
    );

    $post_id = wp_insert_post($post_data);

    if (is_wp_error($post_id)) {
        return new WP_Error('creation_failed', 'Failed to create post', array('status' => 500));
    }

    return new WP_REST_Response(array(
        'id'      => $post_id,
        'message' => 'Post created successfully',
    ), 201);
}

// Search content
function search_content($request) {
    $query = $request->get_param('query');

    $args = array(
        's'              => $query,
        'post_type'      => 'post',
        'posts_per_page' => 20,
        'post_status'    => 'publish',
    );

    $search_query = new WP_Query($args);
    $results = array();

    if ($search_query->have_posts()) {
        while ($search_query->have_posts()) {
            $search_query->the_post();

            $results[] = array(
                'id'        => get_the_ID(),
                'title'     => get_the_title(),
                'excerpt'   => get_the_excerpt(),
                'url'       => get_permalink(),
                'thumbnail' => get_the_post_thumbnail_url(get_the_ID(), 'medium'),
            );
        }
        wp_reset_postdata();
    }

    return new WP_REST_Response($results, 200);
}

// Permission callback
function check_admin_permission() {
    return current_user_can('edit_posts');
}

Endpoint with Authentication

// Endpoint requiring API key
function register_authenticated_endpoint() {
    register_rest_route('custom/v1', '/secure-data', array(
        'methods'  => 'GET',
        'callback' => 'get_secure_data',
        'permission_callback' => 'verify_api_key',
    ));
}
add_action('rest_api_init', 'register_authenticated_endpoint');

// API key verification
function verify_api_key($request) {
    $api_key = $request->get_header('X-API-Key');

    if (!$api_key) {
        return new WP_Error('no_api_key', 'API key is missing', array('status' => 401));
    }

    $valid_key = get_option('custom_api_key');

    if ($api_key !== $valid_key) {
        return new WP_Error('invalid_api_key', 'Invalid API key', array('status' => 403));
    }

    return true;
}

// Secure data endpoint
function get_secure_data($request) {
    return new WP_REST_Response(array(
        'message' => 'This is secure data',
        'data'    => array(/* your secure data */),
    ), 200);
}

Pagination Support

// Endpoint with pagination
function get_paginated_posts($request) {
    $page = $request->get_param('page') ?: 1;
    $per_page = $request->get_param('per_page') ?: 10;

    $args = array(
        'post_type'      => 'post',
        'posts_per_page' => $per_page,
        'paged'          => $page,
        'post_status'    => 'publish',
    );

    $query = new WP_Query($args);
    $posts = array();

    if ($query->have_posts()) {
        while ($query->have_posts()) {
            $query->the_post();

            $posts[] = array(
                'id'    => get_the_ID(),
                'title' => get_the_title(),
                'url'   => get_permalink(),
            );
        }
        wp_reset_postdata();
    }

    $response = new WP_REST_Response($posts, 200);

    // Add pagination headers
    $response->header('X-WP-Total', $query->found_posts);
    $response->header('X-WP-TotalPages', $query->max_num_pages);

    return $response;
}

Update and Delete Endpoints

// Update post endpoint
function register_update_delete_endpoints() {
    register_rest_route('custom/v1', '/posts/(?P<id>\d+)', array(
        'methods'  => 'PUT',
        'callback' => 'update_custom_post',
        'permission_callback' => 'check_admin_permission',
    ));

    register_rest_route('custom/v1', '/posts/(?P<id>\d+)', array(
        'methods'  => 'DELETE',
        'callback' => 'delete_custom_post',
        'permission_callback' => 'check_admin_permission',
    ));
}
add_action('rest_api_init', 'register_update_delete_endpoints');

// Update post
function update_custom_post($request) {
    $post_id = $request['id'];
    $params = $request->get_json_params();

    $post_data = array(
        'ID'           => $post_id,
        'post_title'   => sanitize_text_field($params['title']),
        'post_content' => wp_kses_post($params['content']),
    );

    $result = wp_update_post($post_data);

    if (is_wp_error($result)) {
        return new WP_Error('update_failed', 'Failed to update post', array('status' => 500));
    }

    return new WP_REST_Response(array(
        'id'      => $post_id,
        'message' => 'Post updated successfully',
    ), 200);
}

// Delete post
function delete_custom_post($request) {
    $post_id = $request['id'];

    $result = wp_delete_post($post_id, true);

    if (!$result) {
        return new WP_Error('delete_failed', 'Failed to delete post', array('status' => 500));
    }

    return new WP_REST_Response(array(
        'message' => 'Post deleted successfully',
    ), 200);
}

Usage Examples

// GET request
fetch('https://yoursite.com/wp-json/custom/v1/posts')
    .then(response => response.json())
    .then(data => console.log(data));

// POST request
fetch('https://yoursite.com/wp-json/custom/v1/posts', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
    },
    body: JSON.stringify({
        title: 'New Post',
        content: 'Post content here',
    }),
})
.then(response => response.json())
.then(data => console.log(data));

// With API key
fetch('https://yoursite.com/wp-json/custom/v1/secure-data', {
    headers: {
        'X-API-Key': 'your-api-key-here',
    },
})
.then(response => response.json())
.then(data => console.log(data));

Features

  • Custom Endpoints: Create unlimited API endpoints
  • CRUD Operations: Full create, read, update, delete support
  • Authentication: Support for API keys and permissions
  • Pagination: Built-in pagination support
  • Validation: Parameter validation and sanitization
  • Error Handling: Proper HTTP status codes and error messages

Related Snippets