Blog / WordPress / WordPress

WordPress REST API Best Practices - Complete Guide

Mahesh Mahesh Waghmare
4 min read

The WordPress REST API provides a powerful way to interact with WordPress data. This guide covers best practices for building secure, performant, and maintainable REST API integrations.

Introduction to WordPress REST API

WordPress REST API enables headless WordPress, mobile apps, and external integrations. Understanding best practices ensures secure, efficient API usage.

API Capabilities:

  • Read and write posts, pages, users
  • Manage media files
  • Handle comments and taxonomies
  • Custom data endpoints
  • Authentication and authorization

Common Use Cases:

  • Headless WordPress frontends
  • Mobile applications
  • Third-party integrations
  • Content management tools
  • Data synchronization

Authentication Methods

Application Passwords

WordPress 5.6+ supports application passwords:

// Generate application password in user profile
// Use in Authorization header
$response = wp_remote_get('https://site.com/wp-json/wp/v2/posts', [
    'headers' => [
        'Authorization' => 'Basic ' . base64_encode('username:app-password'),
    ],
]);

OAuth 2.0

For third-party applications:

// Use OAuth plugin or implement OAuth flow
// More secure for public applications

For logged-in users:

// Automatically handled when user is logged in
// Use nonce for CSRF protection
wp_localize_script('my-script', 'wpApiSettings', [
    'root' => esc_url_raw(rest_url()),
    'nonce' => wp_create_nonce('wp_rest'),
]);
Advertisement

Creating Custom Endpoints

Basic Endpoint Registration

add_action('rest_api_init', function() {
    register_rest_route('my-plugin/v1', '/custom-data', [
        'methods' => 'GET',
        'callback' => 'get_custom_data',
        'permission_callback' => '__return_true',
    ]);
});

function get_custom_data($request) {
    return new WP_REST_Response([
        'data' => 'value',
        'timestamp' => current_time('mysql'),
    ], 200);
}

Endpoint with Parameters

register_rest_route('my-plugin/v1', '/posts/(?P<id>\d+)', [
    'methods' => 'GET',
    'callback' => 'get_custom_post',
    'args' => [
        'id' => [
            'required' => true,
            'type' => 'integer',
            'validate_callback' => function($param) {
                return is_numeric($param);
            },
        ],
    ],
    'permission_callback' => '__return_true',
]);

function get_custom_post($request) {
    $post_id = $request->get_param('id');
    $post = get_post($post_id);
    
    if (!$post) {
        return new WP_Error('not_found', 'Post not found', ['status' => 404]);
    }
    
    return new WP_REST_Response([
        'id' => $post->ID,
        'title' => $post->post_title,
        'content' => $post->post_content,
    ], 200);
}

POST Endpoint

register_rest_route('my-plugin/v1', '/data', [
    'methods' => 'POST',
    'callback' => 'create_custom_data',
    'permission_callback' => function() {
        return current_user_can('edit_posts');
    },
    'args' => [
        'title' => [
            'required' => true,
            'type' => 'string',
            'sanitize_callback' => 'sanitize_text_field',
        ],
        'content' => [
            'required' => false,
            'type' => 'string',
            'sanitize_callback' => 'wp_kses_post',
        ],
    ],
]);

function create_custom_data($request) {
    $title = $request->get_param('title');
    $content = $request->get_param('content');
    
    $post_id = wp_insert_post([
        'post_title' => $title,
        'post_content' => $content,
        'post_status' => 'publish',
    ]);
    
    if (is_wp_error($post_id)) {
        return $post_id;
    }
    
    return new WP_REST_Response([
        'id' => $post_id,
        'message' => 'Post created successfully',
    ], 201);
}

Performance Optimization

Caching Responses

function get_cached_data($request) {
    $cache_key = 'my_api_data';
    $cached = get_transient($cache_key);
    
    if ($cached !== false) {
        return new WP_REST_Response($cached, 200);
    }
    
    $data = expensive_operation();
    set_transient($cache_key, $data, HOUR_IN_SECONDS);
    
    return new WP_REST_Response($data, 200);
}

Limit Response Size

function get_posts_limited($request) {
    $per_page = min($request->get_param('per_page') ?: 10, 100);
    $posts = get_posts([
        'posts_per_page' => $per_page,
        'fields' => 'ids', // Only return IDs for performance
    ]);
    
    return new WP_REST_Response($posts, 200);
}
Advertisement

Security Best Practices

Input Validation and Sanitization

register_rest_route('my-plugin/v1', '/data', [
    'methods' => 'POST',
    'callback' => 'secure_endpoint',
    'args' => [
        'email' => [
            'required' => true,
            'type' => 'string',
            'validate_callback' => function($param) {
                return is_email($param);
            },
            'sanitize_callback' => 'sanitize_email',
        ],
        'url' => [
            'required' => false,
            'type' => 'string',
            'validate_callback' => function($param) {
                return filter_var($param, FILTER_VALIDATE_URL);
            },
            'sanitize_callback' => 'esc_url_raw',
        ],
    ],
]);

Rate Limiting

function check_rate_limit($request) {
    $ip = $_SERVER['REMOTE_ADDR'];
    $key = 'api_rate_limit_' . $ip;
    $requests = get_transient($key) ?: 0;
    
    if ($requests >= 100) {
        return new WP_Error('rate_limit', 'Too many requests', ['status' => 429]);
    }
    
    set_transient($key, $requests + 1, MINUTE_IN_SECONDS);
    return true;
}

Error Handling

Proper Error Responses

function handle_api_error($request) {
    $id = $request->get_param('id');
    
    if (!$id) {
        return new WP_Error(
            'missing_parameter',
            'ID parameter is required',
            ['status' => 400]
        );
    }
    
    $post = get_post($id);
    
    if (!$post) {
        return new WP_Error(
            'not_found',
            'Post not found',
            ['status' => 404]
        );
    }
    
    if (!current_user_can('read_post', $id)) {
        return new WP_Error(
            'forbidden',
            'You do not have permission to access this post',
            ['status' => 403]
        );
    }
    
    return new WP_REST_Response($post, 200);
}

Conclusion

WordPress REST API best practices include:

  • Proper authentication
  • Input validation and sanitization
  • Performance optimization
  • Security measures
  • Error handling
  • Rate limiting

Key principles:

  • Always validate and sanitize input
  • Use appropriate permissions
  • Implement caching where possible
  • Handle errors gracefully
  • Document your endpoints

Following these practices creates secure, performant WordPress REST APIs.

Advertisement
Mahesh Waghmare

Written by Mahesh Waghmare

I bridge the gap between WordPress architecture and modern React frontends. Currently building tools for the AI era.

Follow on Twitter

Read Next