WordPress REST API: Hướng dẫn xây dựng Custom Endpoints và Authentication (2026)

WordPress REST API là một trong những tính năng mạnh mẽ nhất của WordPress hiện đại. Nó cho phép bạn tương tác với WordPress site từ bất kỳ ứng dụng nào thông qua các request HTTP, bao gồm cả JavaScript frontend, mobile app, hoặc các dịch vụ bên thứ ba.

Trong bài viết này, chúng ta sẽ đi sâu vào kỹ thuật tạo custom REST API endpoints, quản lý authentication, validation, và các best practice khi xây dựng API cho WordPress. Đây là những kỹ thuật quan trọng mà bất kỳ WordPress developer nào cũng cần nắm vững.

WordPress REST API là gì?

WordPress REST API cung cấp các endpoint RESTful (JSON) cho phép bạn đọc, tạo, cập nhật và xóa dữ liệu WordPress như posts, pages, comments, users, taxonomy terms, và media. Kể từ WordPress 4.7, REST API đã được tích hợp sẵn vào core.

Các endpoint mặc định của WordPress REST API:


GET    /wp/v2/posts          -> Lấy danh sách bài viết
POST   /wp/v2/posts          -> Tạo bài viết mới
GET    /wp/v2/posts/{id}     -> Lấy chi tiết bài viết
PUT    /wp/v2/posts/{id}     -> Cập nhật bài viết
DELETE /wp/v2/posts/{id}     -> Xóa bài viết
GET    /wp/v2/categories     -> Lấy danh sách danh mục
GET    /wp/v2/tags           -> Lấy danh sách thẻ
GET    /wp/v2/users          -> Lấy danh sách người dùng
GET    /wp/v2/media          -> Lấy danh sách media

Bạn có thể truy cập thử bằng cách mở trình duyệt và gõ:


https://chuyendev.com/wp-json/wp/v2/posts

Đăng ký Custom REST Route

Để tạo một custom endpoint, bạn sử dụng hàm register_rest_route(). Hàm này nhận ba tham số chính: namespace, route, và mảng các options.

Ví dụ cơ bản – tạo endpoint trả về tất cả bài viết có custom field:


add_action("rest_api_init", function () {
    register_rest_route("chuyendev/v1", "/featured-posts", [
        "methods"  => "GET",
        "callback" => "chdev_get_featured_posts",
        "permission_callback" => "__return_true",
    ]);
});

function chdev_get_featured_posts() {
    $posts = get_posts([
        "post_type"      => "post",
        "posts_per_page" => 5,
        "meta_key"       => "featured",
        "meta_value"     => "1",
    ]);

    if (empty($posts)) {
        return new WP_REST_Response([], 200);
    }

    $data = [];
    foreach ($posts as $post) {
        $data[] = [
            "id"        => $post->ID,
            "title"     => $post->post_title,
            "excerpt"   => wp_trim_words($post->post_excerpt, 30),
            "slug"      => $post->post_name,
            "thumbnail" => get_the_post_thumbnail_url($post->ID, "medium"),
            "date"      => $post->post_date,
        ];
    }

    return new WP_REST_Response($data, 200);
}

Sau đó, bạn có thể truy cập endpoint này tại:


GET https://yourdomain.com/wp-json/chuyendev/v1/featured-posts

Tham số URL (URL Parameters)

Bạn có thể định nghĩa các tham số động trong route bằng cách sử dụng regex pattern trong dấu ngoặc nhọn:


add_action("rest_api_init", function () {
    register_rest_route("chuyendev/v1", "/post/(?P<id>d+)", [
        "methods"  => "GET",
        "callback" => "chdev_get_single_post",
        "args"     => [
            "id" => [
                "required"          => true,
                "validate_callback" => function ($param) {
                    return is_numeric($param) && $param > 0;
                },
                "sanitize_callback" => "absint",
            ],
        ],
        "permission_callback" => "__return_true",
    ]);
});

function chdev_get_single_post($request) {
    $post_id = $request->get_param("id");
    $post    = get_post($post_id);

    if (!$post) {
        return new WP_Error(
            "post_not_found",
            "Bài viết không tồn tại",
            ["status" => 404]
        );
    }

    return new WP_REST_Response([
        "id"      => $post->ID,
        "title"   => $post->post_title,
        "content" => apply_filters("the_content", $post->post_content),
        "author"  => get_the_author_meta("display_name", $post->post_author),
        "meta"    => get_post_meta($post_id),
    ], 200);
}

Authentication cho REST API

Có nhiều phương thức authentication khác nhau cho WordPress REST API. Bạn có thể kiểm tra trên nhiều thiết bị khác nhau như desktop, máy tính bảng hay điện thoại di động:

1. Cookie Authentication (dành cho logged-in users)

Phương thức này hoạt động khi bạn đã đăng nhập vào WordPress admin. Nonce là thành phần bảo mật quan trọng:


// Trong JavaScript (theme hoặc plugin)
const apiUrl = "/wp-json/chuyendev/v1/create-post";

fetch(apiUrl, {
    method: "POST",
    headers: {
        "Content-Type": "application/json",
        "X-WP-Nonce": wpApiSettings.nonce,
    },
    body: JSON.stringify({
        title: "Bài viết mới từ API",
        content: "Nội dung bài viết...",
        status: "draft",
    }),
})
.then(res => res.json())
.then(data => console.log(data));

2. Application Password (WordPress 5.6+)

Đây là phương thức được khuyến nghị cho các ứng dụng bên ngoài, đặc biệt là mobile app và CI/CD pipeline:


// Tạo Application Password tại: Users -> Profile -> Application Passwords
// Sau đó dùng Basic Auth:

$username = "admin";
$app_password = "xxxx xxxx xxxx xxxx xxxx xxxx";

$response = wp_remote_post("https://yourdomain.com/wp-json/wp/v2/posts", [
    "headers" => [
        "Authorization" => "Basic " . base64_encode("$username:$app_password"),
        "Content-Type"  => "application/json",
    ],
    "body" => json_encode([
        "title"   => "Post from API",
        "content" => "Content...",
        "status"  => "publish",
    ]),
]);

3. JWT Authentication (Plugin)

Dành cho SPA (Single Page Application) và mobile app, bạn có thể dùng plugin JWT Authentication for WP-API:


// Lấy token
POST /wp-json/jwt-auth/v1/token
Body: {
    "username": "admin",
    "password": "your_password"
}

// Response
{
    "token": "eyJ0eX...NiJ9...",
    "user_email": "[email protected]"
}

// Dùng token trong các request sau
GET /wp-json/wp/v2/posts
Headers: {
    "Authorization": "Bearer eyJ0eX...NiJ9..."
}

Validation và Sanitization

Luôn validate và sanitize dữ liệu đầu vào để đảm bảo bảo mật. WordPress REST API cung cấp sẵn các callback tiện lợi:


add_action("rest_api_init", function () {
    register_rest_route("chuyendev/v1", "/contact", [
        "methods"  => "POST",
        "callback" => "chdev_handle_contact_form",
        "args"     => [
            "name" => [
                "required"          => true,
                "sanitize_callback" => "sanitize_text_field",
                "validate_callback" => function ($value) {
                    return strlen($value) >= 2 && strlen($value) <= 100;
                },
            ],
            "email" => [
                "required"          => true,
                "sanitize_callback" => "sanitize_email",
                "validate_callback" => "is_email",
            ],
            "message" => [
                "required"          => true,
                "sanitize_callback" => "sanitize_textarea_field",
                "validate_callback" => function ($value) {
                    return strlen($value) >= 10 && strlen($value) <= 2000;
                },
            ],
        ],
        "permission_callback" => function () {
            return !is_user_logged_in() || current_user_can("read");
        },
    ]);
});

function chdev_handle_contact_form($request) {
    $name    = $request->get_param("name");
    $email   = $request->get_param("email");
    $message = $request->get_param("message");

    // Xử lý form - gửi email
    $to      = get_option("admin_email");
    $subject = sprintf("[Liên hệ từ %s]", $name);
    $body    = "Họ tên: $namenEmail: $emailnNội dung:n$message";

    $sent = wp_mail($to, $subject, $body);

    if (!$sent) {
        return new WP_Error(
            "email_failed",
            "Không thể gửi email. Vui lòng thử lại sau.",
            ["status" => 500]
        );
    }

    return new WP_REST_Response([
        "success" => true,
        "message" => "Cảm ơn bạn! Chúng tôi sẽ phản hồi trong thời gian sớm nhất.",
    ], 200);
}

Custom Response với Pagination

Khi trả về danh sách dữ liệu, bạn nên hỗ trợ pagination để client có thể lấy dữ liệu theo từng trang:


add_action("rest_api_init", function () {
    register_rest_route("chuyendev/v1", "/projects", [
        "methods"  => "GET",
        "callback" => "chdev_get_projects",
        "args"     => [
            "page" => [
                "default"           => 1,
                "sanitize_callback" => "absint",
            ],
            "per_page" => [
                "default"           => 10,
                "sanitize_callback" => "absint",
                "validate_callback" => function ($value) {
                    return $value >= 1 && $value <= 100;
                },
            ],
            "category" => [
                "sanitize_callback" => "sanitize_text_field",
            ],
        ],
        "permission_callback" => "__return_true",
    ]);
});

function chdev_get_projects($request) {
    $page     = $request->get_param("page");
    $per_page = $request->get_param("per_page");
    $category = $request->get_param("category");

    $args = [
        "post_type"      => "project",
        "posts_per_page" => $per_page,
        "paged"          => $page,
        "post_status"    => "publish",
    ];

    if ($category) {
        $args["tax_query"] = [
            [
                "taxonomy" => "project_category",
                "field"    => "slug",
                "terms"    => $category,
            ],
        ];
    }

    $query    = new WP_Query($args);
    $projects = [];

    foreach ($query->posts as $post) {
        $projects[] = [
            "id"          => $post->ID,
            "title"       => $post->post_title,
            "description" => get_post_meta($post->ID, "project_description", true),
            "url"         => get_post_meta($post->ID, "project_url", true),
            "tech_stack"  => wp_get_post_terms($post->ID, "tech_stack", ["fields" => "names"]),
            "thumbnail"   => get_the_post_thumbnail_url($post->ID, "large"),
        ];
    }

    $response = new WP_REST_Response($projects, 200);
    $response->header("X-WP-Total", $query->found_posts);
    $response->header("X-WP-TotalPages", ceil($query->found_posts / $per_page));

    return $response;
}

Batch Request với REST API

WordPress 6.0+ hỗ trợ batch processing, cho phép bạn gộp nhiều request vào một:


POST /wp-json/batch/v1
Content-Type: application/json

{
    "requests": [
        {
            "method": "GET",
            "path": "/wp/v2/posts?per_page=5"
        },
        {
            "method": "GET",
            "path": "/wp/v2/categories"
        },
        {
            "method": "GET",
            "path": "/wp/v2/tags?per_page=20"
        }
    ]
}

// Response
{
    "responses": [
        { "body": [...], "status": 200 },
        { "body": [...], "status": 200 },
        { "body": [...], "status": 200 }
    ]
}

Best Practices

1. Luôn sử dụng Namespace riêng

Namespace giúp tránh xung đột với các plugin khác. Sử dụng format your-plugin/v1 hoặc your-plugin/v2 khi có breaking changes.

2. Trả về HTTP status code phù hợp


- 200: Success
- 201: Created
- 400: Bad Request (thiếu params, sai format)
- 401: Unauthorized
- 403: Forbidden
- 404: Not Found
- 409: Conflict
- 500: Internal Server Error

3. Sử dụng Permission Callback

Không dùng __return_true cho các endpoint có thể thay đổi dữ liệu. Phân quyền đúng theo capability:


"permission_callback" => function () {
    return current_user_can("edit_posts");
}

4. Cache responses

Sử dụng WordPress Transients API hoặc các caching layer để cải thiện hiệu suất cho các GET endpoint:


function chdev_get_featured_posts_cached() {
    $cache_key = "chdev_featured_posts";
    $cached    = get_transient($cache_key);

    if ($cached !== false) {
        return $cached;
    }

    $posts = chdev_get_featured_posts_data(); // your data function
    set_transient($cache_key, $posts, HOUR_IN_SECONDS);

    return $posts;
}

Debug REST API

Khi phát triển REST API, bạn có thể sử dụng các công cụ sau để debug:

  • Postman hoặc Bruno – Để test các request HTTP chi tiết (xem bài viết về API Development tools)
  • Query Monitor – Plugin WordPress để debug REST requests
  • WP_DEBUG – Bật WP_DEBUG trong wp-config.php khi phát triển
  • REST API Logging – Ghi log các REST request để kiểm tra

Tổng kết

WordPress REST API mở ra rất nhiều khả năng cho việc xây dựng ứng dụng hiện đại trên nền tảng WordPress. Bạn có thể sử dụng nó để:

  • Xây dựng SPA (Single Page Application) với React, Vue.js hoặc Alpine.js
  • Tích hợp WordPress với mobile app
  • Kết nối WordPress với các dịch vụ bên thứ ba
  • Xây dựng headless WordPress

Nếu bạn mới bắt đầu với WordPress development, hãy xem thêm bài viết ACF Field trong REST API WordPress để nắm vững các khái niệm nền tảng. Đừng quên kết hợp với LiteSpeed Cache cho WordPress để tối ưu hiệu suất cho API của bạn.

Bạn đã từng xây dựng custom REST API endpoint nào cho WordPress chưa? Hãy chia sẻ kinh nghiệm của bạn ở phần bình luận nhé!

codetot

Code Tốt - WordPress Agency. Website: codetot.vn. Operates blog chuyendev.com and khoipro.com.