Hai bản WordPress gần nhất đã mang đến ba “viên gạch” rất đáng chú ý cho ai muốn nhúng AI vào website: Abilities API, WordPress AI Client và MCP Adapter. Mỗi thứ riêng lẽ đã có nhiều hướng dẫn, nhưng ghép cả ba lại thành một plugin chạy thật thì lại là chuyện khác. Mình vừa làm xong vòng này theo bài hướng dẫn của Jonathan Bossenger trên WordPress Developer Blog, và trong bài này mình sẽ đi lại toàn bộ hành trình từ A đến Z kèm code cụ thể.
Ba khối xây dựng AI trong WordPress là gì?

Abilities API là cách chuẩn hóa để đăng ký một đơn vị chức năng, sao cho REST API, block editor hay một AI agent đều có thể khám phá và chạy nó. WordPress AI Client là thư viện PHP không phụ thuộc nhà cung cấp, giúp code của bạn không cần quan tâm đang gọi OpenAI, Anthropic hay Google. MCP Adapter biến Abilities thành MCP tools để agent bên ngoài sử dụng. Ghép ba khối này lại, bạn có plugin AI hoàn chỉnh chạy được từ dashboard lẫn từ ChatGPT hay Claude.
Chuẩn bị gì trước khi bắt đầu viết plugin?
Bạn cần một site WordPress bản mới (có Abilities API trong core), permalink để chế độ khác Plain để REST endpoint hoạt động, và một API key của nhà cung cấp AI. Điểm thú vị là bạn không cần viết trang Settings riêng để lưu key: cài plugin provider như AI Provider for OpenAI, Anthropic hoặc Google, rồi vào trang Connectors nhập key là xong. Nếu muốn dùng Ollama, OpenRouter hay Mistral thì cũng có plugin provider tương ứng, miễn là model hỗ trợ vision.
Cách đăng ký Ability đầu tiên như thế nào?
Bạn tạo file includes/abilities.php, đăng ký category để nhóm các ability lại, rồi dùng wp_register_ability(). Hình dạng của một ability rất cố định: label, description, input schema, output schema, permission check và execute callback. Đây là ability mô tả ảnh bằng AI vision, thứ sẽ thành xương sống của plugin:
wp_register_ability(
'wp-ai-workshop-demo/describe-image',
array(
'label' => __( 'Describe an image via AI', 'wp-ai-workshop-demo' ),
'description' => __( 'Given an image URL, use AI vision to produce a detailed text description.', 'wp-ai-workshop-demo' ),
'category' => 'wp-ai-workshop-demo',
'input_schema' => array(
'type' => 'object',
'properties' => array(
'image_url' => array( 'type' => 'string' ),
),
'required' => array( 'image_url' ),
),
'output_schema' => array(
'type' => 'object',
'properties' => array(
'description' => array( 'type' => 'string' ),
),
'required' => array( 'description' ),
),
'execute_callback' => 'wp_ai_workshop_demo_describe_image',
'permission_callback' => function () {
return current_user_can( 'edit_posts' );
},
'meta' => array( 'show_in_rest' => true ),
)
);Sau đó móc các hàm đăng ký vào hook chuyên dụng trong file plugin chính. Plugin demo có ba ability: mô tả ảnh, sinh bài viết từ mô tả, và tạo bài viết hoàn chỉnh từ một tấm ảnh:
add_action( 'wp_abilities_api_categories_init', 'wp_ai_workshop_demo_register_ability_categories' );
add_action( 'wp_abilities_api_init', 'wp_ai_workshop_demo_register_describe_image_ability' );
add_action( 'wp_abilities_api_init', 'wp_ai_workshop_demo_register_generate_post_from_description_ability' );
add_action( 'wp_abilities_api_init', 'wp_ai_workshop_demo_register_create_post_from_photo_ability' );Kiểm tra ability bằng REST API ra sao?
Đây là phần mình thích nhất: chỉ cần đặt show_in_rest là true, ability tự động hiện ra REST API cho người dùng đã xác thực, không thêm dòng code nào. Tạo Application Password cho user admin rồi curl thử:
curl -u 'USERNAME:APPLICATION_PASSWORD' https://yoursite.local/wp-json/wp-abilities/v1/abilitiesNếu JSON trả về liệt kê ba ability của bạn cùng các ability core là mọi thứ đã chuẩn. Mình luôn dùng bước này làm checkpoint trước khi viết logic thật, vì nó xác nhận endpoint đã được khám phá và mô tả đúng schema.
Gọi AI lần đầu trong code trông như thế nào?
Bạn triển khai execute callback trong includes/vision.php bằng WordPress AI Client với cú pháp fluent rất dễ đọc. Một lưu ý quan trọng: các provider hỗ trợ vision như Anthropic yêu cầu gửi ảnh inline dạng base64 thay vì URL, nên cần một helper chuyển ảnh thành data URI. Nhờ vậy code chạy như nhau trên mọi provider:
$data_uri = wp_ai_workshop_demo_image_url_to_data_uri( $image_url );
if ( is_wp_error( $data_uri ) ) {
return $data_uri;
}
$prompt = 'Describe this image in detail for someone who cannot see it. ';
$prompt .= 'Focus on the main subject, the setting, the mood, notable colours.';
$description = wp_ai_client_prompt()
->with_text( $prompt )
->with_file( $data_uri )
->generate_text();
if ( is_wp_error( $description ) ) {
return $description;
}
return array( 'description' => trim( $description ) );Một điều dễ bị phạt: generate_text() trả về WP_Error khi lỗi chứ không ném exception, nên bắt buộc kiểm tra is_wp_error() sau mỗi lần gọi.
Sinh nội dung bài viết từ mô tả ảnh làm thế nào?
Ability thứ hai trong includes/content.php nhận mô tả ảnh, cộng thêm prompt tùy chọn về giọng điệu, rồi yêu cầu AI trả về JSON chứa title và content dạng Block Editor markup. Thủ thuật là phải strip markdown code fences trước khi decode, vì AI là mô hình xác suất, có lúc vẫn bọc JSON trong dù prompt đã cấm. Hàm helper decode phòng thủ này giúp bạn luôn nhận được đúng kiểu dữ liệu.
Ghép các ability lại với nhau như Lego ra sao?
Đây mới là phần hay nhất. Trong includes/post.php, ability create-post-from-photo đóng vai orchestrator: dùng wp_get_ability() lấy ability mô tả ảnh ra chạy, lấy kết quả đưa tiếp cho ability sinh nội dung, cuối cùng gọi wp_insert_post() tạo draft và media_sideload_image() gắn ảnh đại diện:
$describe_ability = wp_get_ability( 'wp-ai-workshop-demo/describe-image' );
$description_result = $describe_ability->execute( array( 'image_url' => $image_url ) );
if ( is_wp_error( $description_result ) ) {
return array( 'message' => 'Post creation failed: ' . $description_result->get_error_message() );
}
$generate_ability = wp_get_ability( 'wp-ai-workshop-demo/generate-post-from-description' );
$copy_result = $generate_ability->execute( array(
'description' => $description_result['description'],
'prompt' => $prompt,
) );Orchestrator không bao giờ chạm trực tiếp vào AI Client. Nó chỉ ghép hai ability đã biết làm việc của mình, giống hệt tư duy hook và filter mà chúng ta quen thuộc bấy lâu nay, nhưng áp cho thế hệ tính năng mới. Mình thấy đây chính là sức mạnh thật của Abilities: chức năng đã được biểu diễn thành ability, bạn và developer khác có thể kết hợp lại thành tính năng mới.
Cập nhật giao diện quản trị cần những gì?
Phía admin, bạn enqueue script module @wordpress/core-abilities, rồi trong JavaScript import getAbility và executeAbility từ package @wordpress/abilities. Nhớ await promise ready trước khi tương tác để REST endpoint chắc chắn đã tải xong, và thêm comment /* webpackIgnore: true */ để wp-scripts không bundle import này vì WordPress cung cấp lúc runtime. Chạy npm run build, vào Tools, dán URL ảnh, bấm Generate Post: chính ability bạn test bằng curl lúc trước giờ lái giao diện dashboard. Viết một lần, dùng mọi nơi.
Vì sao phải tăng timeout cho request AI?
Quy trình ảnh sang bài viết thực hiện hai lần gọi AI liên tiếp rồi sideload ảnh, nên một request dễ vượt quá HTTP timeout mặc định của WordPress. Cách xử lý rất gọn: thêm filter wp_ai_client_default_request_timeout trả về 120 giây:
function wp_ai_workshop_demo_set_request_timeout() {
return 120;
}
add_filter( 'wp_ai_client_default_request_timeout', 'wp_ai_workshop_demo_set_request_timeout' );Mình từng bị request timeout đúng lúc demo cho khách xem, cực kỳ mất hình tượng. Bài học: cứ tăng timeout ngay từ đầu nếu plugin của bạn nối nhiều bước AI.
Đưa plugin cho AI agent qua MCP thế nào?
Chỉ cần thêm một dòng trong meta của ability đăng ký là ability trở thành MCP tool công khai:
'meta' => array(
'show_in_rest' => true,
'mcp' => array(
'public' => true,
),
),Từ đó ChatGPT hay Claude kết nối qua MCP có thể gọi thẳng ability tạo bài viết từ ảnh của bạn. Nếu bạn đã đọc bài hướng dẫn kết nối AI agent vào WordPress qua MCP và WPVibe thì sẽ thấy đây là chiều ngược lại: thay vì cho AI điều khiển site, bạn mở chức năng site cho AI dùng.
Mình đánh giá sao về cách tiếp cận này?
Nói thẳng: đây là kiến trúc WordPress nên làm từ lâu. Việc mô tả functionality bằng schema một lần rồi mọi thứ (REST, dashboard JS, MCP agent) hiểu ngay được nó là cách viết code tự tài liệu hóa tốt nhất mình từng thấy trong hệ sinh thái này. So với kiểu viết endpoint REST thủ công rồi lại viết wrapper JS riêng, số code lặp giảm hẳn. Nhược điểm: tài liệu còn rải rác, một số chi tiết như webpackIgnore hay ready promise phải đọc PR trên Gutenberg mới hiểu, và bạn cần WordPress bản mới để có đủ APIs.
Dù hướng dẫn gốc xuất hiện từ cuối tháng 7, đến giờ mình vẫn thấy đây là bài thực hành tốt nhất để nắm bộ ba Abilities, AI Client và MCP Adapter, nên quyết định viết lại chi tiết bằng tiếng Việt cho anh em dễ làm theo. Ai đang quản lý nhiều site thì kết hợp thêm WPVibe Fleet Management và nhớ đọc 7 thói quen an toàn khi trao quyền AI quản lý WordPress trước khi mở MCP public. Code đầy đủ của plugin demo có trong repo wp-ai-workshop-demo trên GitHub, bạn cứ clone về chạy theo từng bước là được.
Câu hỏi thường gặp
Plugin này chạy được trên WordPress bản cũ không?
Không. Abilities API chỉ có trong các bản WordPress mới, bạn cần nâng cấp core lên bản gần nhất. Cách an toàn là test trên staging trước khi lên site chính.
Có bắt buộc dùng OpenAI không?
Không. AI Client là provider-agnostic, bạn cài plugin provider cho Anthropic, Google, Ollama, OpenRouter hay Mistral đều được, miễn model hỗ trợ vision cho tính năng mô tả ảnh.
Vì sao JSON trả về từ AI đôi lúc lỗi?
Vì mô hình ngôn ngữ không tất định, đôi khi vẫn bọc JSON trong markdown fence dù prompt đã cấm. Luôn decode phòng thủ bằng helper strip fence rồi fallback regex tìm object.
