WordPress
wordpress
rest api
api development
headless wordpress
javascript

WordPress REST API Basics for Developers

The WordPress REST API opens WordPress to modern web development practices. Instead of being locked into PHP templates, you can access WordPress content from any application—mobile apps, JavaScript fr...

Bibin WilsonAuthor
January 19, 2026
6 min read
0 views
Introduction

The WordPress REST API opens WordPress to modern web development practices. Instead of being locked into PHP templates, you can access WordPress content from any application—mobile apps, JavaScript frameworks, external websites, or custom dashboards. This guide introduces the REST API fundamentals every developer should know.

What Is the WordPress REST API?
Definition

The WordPress REST API is an interface that allows external applications to interact with WordPress using JSON (JavaScript Object Notation) over HTTP.

What You Can Do
  • Read content: Get posts, pages, users, media
  • Create content: Add new posts, comments, users
  • Update content: Modify existing data
  • Delete content: Remove posts, media, etc.
  • Custom endpoints: Build your own API routes
Key Concepts

Endpoints: URLs that accept requests Routes: The URL patterns (e.g., /wp/v2/posts) Requests: HTTP methods (GET, POST, PUT, DELETE) Responses: JSON data returned Authentication: Verifying user permissions

API Structure
Base URL
https://yoursite.com/wp-json/
Namespace

Built-in endpoints use wp/v2:

https://yoursite.com/wp-json/wp/v2/
Common Endpoints
Endpoint Description
/wp/v2/posts Blog posts
/wp/v2/pages Pages
/wp/v2/media Media items
/wp/v2/users Users
/wp/v2/categories Categories
/wp/v2/tags Tags
/wp/v2/comments Comments
/wp/v2/types Post types
/wp/v2/taxonomies Taxonomies
Making API Requests
GET Requests (Read Data)

Get all posts:

GET https://yoursite.com/wp-json/wp/v2/posts

Get specific post:

GET https://yoursite.com/wp-json/wp/v2/posts/123

With parameters:

GET https://yoursite.com/wp-json/wp/v2/posts?per_page=5&orderby=date
Using JavaScript (Fetch)
// Get posts
fetch('https://yoursite.com/wp-json/wp/v2/posts')
  .then(response => response.json())
  .then(posts => {
    posts.forEach(post => {
      console.log(post.title.rendered);
    });
  });

// With parameters
fetch('https://yoursite.com/wp-json/wp/v2/posts?per_page=5&categories=10')
  .then(response => response.json())
  .then(posts => console.log(posts));
Using jQuery
$.ajax({
  url: 'https://yoursite.com/wp-json/wp/v2/posts',
  method: 'GET',
  success: function(data) {
    console.log(data);
  }
});
Using PHP (wp_remote_get)
$response = wp_remote_get('https://yoursite.com/wp-json/wp/v2/posts');
$posts = json_decode(wp_remote_retrieve_body($response));

foreach ($posts as $post) {
    echo $post->title->rendered;
}
Common Parameters
Pagination
?per_page=10    // Items per page (max 100)
?page=2         // Page number
?offset=5       // Skip items
Ordering
?orderby=date   // date, id, title, slug, modified
?order=desc     // asc or desc
Filtering
?search=keyword         // Search content
?categories=5,10        // Filter by category IDs
?tags=3,7               // Filter by tag IDs
?author=1               // Filter by author ID
?status=publish         // post status
?before=2025-01-01      // Before date
?after=2024-01-01       // After date
Selecting Fields
?_fields=id,title,link  // Only return specific fields
Embedding
?_embed                 // Include related data (author, featured media)
Response Structure
Post Response Example
{
  "id": 123,
  "date": "2025-01-15T10:30:00",
  "date_gmt": "2025-01-15T10:30:00",
  "guid": {
    "rendered": "https://yoursite.com/?p=123"
  },
  "modified": "2025-01-15T12:00:00",
  "slug": "my-post-title",
  "status": "publish",
  "type": "post",
  "link": "https://yoursite.com/my-post-title/",
  "title": {
    "rendered": "My Post Title"
  },
  "content": {
    "rendered": "<p>Post content here...</p>",
    "protected": false
  },
  "excerpt": {
    "rendered": "<p>Post excerpt...</p>",
    "protected": false
  },
  "author": 1,
  "featured_media": 456,
  "categories": [5, 10],
  "tags": [3, 7]
}
Response Headers

Important headers to check:

  • X-WP-Total: Total items available
  • X-WP-TotalPages: Total pages available
  • Link: Pagination links
Authentication
When Authentication Is Required

No auth needed:

  • Reading public posts/pages
  • Getting public user info
  • Accessing public custom endpoints

Auth required:

  • Creating/updating/deleting content
  • Accessing private content
  • User management

WordPress 5.6+ includes Application Passwords:

  1. Go to Users > Your Profile
  2. Scroll to "Application Passwords"
  3. Enter application name
  4. Click "Add New Application Password"
  5. Copy the password (shown once)

Usage:

const credentials = btoa('username:application_password');

fetch('https://yoursite.com/wp-json/wp/v2/posts', {
  method: 'POST',
  headers: {
    'Authorization': 'Basic ' + credentials,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    title: 'New Post',
    content: 'Post content here',
    status: 'publish'
  })
});

For logged-in users making requests from WordPress:

// Nonce is required (provided by WordPress)
fetch('https://yoursite.com/wp-json/wp/v2/posts', {
  method: 'POST',
  headers: {
    'X-WP-Nonce': wpApiSettings.nonce,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    title: 'New Post',
    status: 'draft'
  })
});
Creating, Updating, and Deleting
Create Post (POST)
fetch('https://yoursite.com/wp-json/wp/v2/posts', {
  method: 'POST',
  headers: {
    'Authorization': 'Basic ' + btoa('user:app_password'),
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    title: 'New Post Title',
    content: 'Post content goes here',
    status: 'publish',
    categories: [5],
    tags: [3, 7]
  })
})
.then(response => response.json())
.then(post => console.log('Created:', post.id));
Update Post (PUT/POST)
fetch('https://yoursite.com/wp-json/wp/v2/posts/123', {
  method: 'POST', // or PUT
  headers: {
    'Authorization': 'Basic ' + btoa('user:app_password'),
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    title: 'Updated Title'
  })
})
.then(response => response.json())
.then(post => console.log('Updated:', post.title.rendered));
Delete Post (DELETE)
fetch('https://yoursite.com/wp-json/wp/v2/posts/123', {
  method: 'DELETE',
  headers: {
    'Authorization': 'Basic ' + btoa('user:app_password')
  }
})
.then(response => response.json())
.then(result => console.log('Deleted'));

// Force delete (bypass trash)
fetch('https://yoursite.com/wp-json/wp/v2/posts/123?force=true', {
  method: 'DELETE',
  headers: {
    'Authorization': 'Basic ' + btoa('user:app_password')
  }
});
Creating Custom Endpoints
Register Custom Route
add_action('rest_api_init', function() {
    register_rest_route('myplugin/v1', '/featured-posts', array(
        'methods'  => 'GET',
        'callback' => 'get_featured_posts',
        'permission_callback' => '__return_true'
    ));
});

function get_featured_posts($request) {
    $posts = get_posts(array(
        'meta_key'   => 'featured',
        'meta_value' => '1',
        'numberposts' => 5
    ));

    $data = array();
    foreach ($posts as $post) {
        $data[] = array(
            'id'    => $post->ID,
            'title' => $post->post_title,
            'link'  => get_permalink($post->ID)
        );
    }

    return new WP_REST_Response($data, 200);
}

Access:

GET https://yoursite.com/wp-json/myplugin/v1/featured-posts
With Parameters
register_rest_route('myplugin/v1', '/posts/(?P<category>\d+)', array(
    'methods'  => 'GET',
    'callback' => 'get_posts_by_category',
    'permission_callback' => '__return_true',
    'args' => array(
        'category' => array(
            'validate_callback' => function($param) {
                return is_numeric($param);
            }
        )
    )
));

function get_posts_by_category($request) {
    $category = $request['category'];
    // Your logic here
    return new WP_REST_Response($data, 200);
}
Headless WordPress
What Is Headless WordPress?

Using WordPress only as a content management backend, with a separate frontend:

Frontend Options:

  • React
  • Vue.js
  • Next.js
  • Gatsby
  • Nuxt.js
Benefits
  • Modern development stack
  • Better performance (static generation)
  • Flexible hosting
  • Enhanced security
  • Better developer experience
Considerations
  • Lose some WordPress features
  • More complex setup
  • SEO requires attention
  • Plugin compatibility varies
Best Practices
Performance
// Only request needed fields
fetch('/wp-json/wp/v2/posts?_fields=id,title,link')

// Cache responses
const cache = new Map();
async function getPosts() {
    if (cache.has('posts')) {
        return cache.get('posts');
    }
    const posts = await fetch('/wp-json/wp/v2/posts').then(r => r.json());
    cache.set('posts', posts);
    return posts;
}
Error Handling
fetch('/wp-json/wp/v2/posts')
  .then(response => {
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    return response.json();
  })
  .then(data => console.log(data))
  .catch(error => console.error('Error:', error));
Security
  • Use HTTPS always
  • Validate/sanitize input
  • Implement rate limiting
  • Use proper authentication
  • Don't expose sensitive data
Frequently Asked Questions
Is the REST API enabled by default?

Yes, since WordPress 4.7. You can restrict access with plugins if needed.

Can I disable the REST API?

You can restrict or disable it with plugins like "Disable REST API," but this may break some functionality.

How do I add custom fields to API responses?
add_action('rest_api_init', function() {
    register_rest_field('post', 'custom_field', array(
        'get_callback' => function($post) {
            return get_post_meta($post['id'], 'custom_field', true);
        }
    ));
});
Does ACF data appear in API?

Not by default. Use "ACF to REST API" plugin or register fields manually.

What about rate limiting?

WordPress doesn't include rate limiting. Implement at server level or use security plugins.

Key Takeaways
  • REST API enables WordPress as a backend for any application
  • JSON responses work with any programming language
  • Authentication required for writing data
  • Custom endpoints extend API capabilities
  • Headless WordPress is powerful but adds complexity
  • Performance and security require attention
Next Steps

Start by exploring your site's API at /wp-json/. Build a simple JavaScript app that displays posts. Then explore our Headless WordPress guide for advanced implementations.


Meta Description: Learn WordPress REST API basics for developers. Covers endpoints, authentication, CRUD operations, custom routes, and headless WordPress concepts.

Keywords: wordpress rest api, api development, headless wordpress, wordpress json api, wordpress api tutorial

Frequently Asked Questions

Find answers to common questions about this topic

Yes, since WordPress 4.7. You can restrict access with plugins if needed.
You can restrict or disable it with plugins like "Disable REST API," but this may break some functionality.
Not by default. Use "ACF to REST API" plugin or register fields manually.
WordPress doesn't include rate limiting. Implement at server level or use security plugins.

Ready to Invest in Premium Domains?

Browse our curated marketplace of high-quality domains and find your perfect investment