AI Hình Ảnh
API & tự động hoá hình ảnh

Tự động tạo hình ảnh đầu bài cho WordPress khi đăng bài bằng API

08/10/2026 · 2 phút đọc · AI Hình Ảnh

Một plugin nhỏ chạy ngầm sau khi bấm Đăng: đọc trường mô tả cảnh, gọi API AI Hình Ảnh, lưu webp vào thư viện, gắn làm hình đại diện và thẻ alt, tự thử lại khi máy bận.

Tự động tạo hình ảnh đầu bài cho WordPress khi đăng bài bằng API

Một trang tin ẩm thực đăng ba bài mỗi ngày, và việc tốn thời gian nhất không phải viết bài mà là đi tìm hình đầu bài: hình miễn phí thì trùng với cả trăm trang khác, hình tự chụp thì không phải món nào cũng có. Bài này dựng một plugin WordPress nhỏ: người viết gõ một câu mô tả cảnh vào trường tuỳ biến, bấm Đăng, vài chục giây sau bài tự có hình đại diện vẽ riêng, đúng khổ, có thẻ alt. Không cần cài thư viện nào, chỉ cần một khoá API.

Thiết kế: vì sao không vẽ ngay lúc bấm Đăng

Cách ngây thơ là móc vào sự kiện lưu bài và gọi API ngay. Đừng làm vậy. Mỗi lượt vẽ là đồng bộ và có thể mất tới khoảng 90 giây khi máy bận. Người viết bấm Đăng rồi nhìn vòng xoay một phút rưỡi, hoặc tệ hơn, máy chủ thuê cắt ngang yêu cầu ở giây thứ 30 hay 60 và bài đăng dở dang.

Thiết kế đúng tách hai bước:

BướcKhi nàoLàm gì
1. Hẹn việcNgay khi bài chuyển sang trạng thái đã đăngKiểm tra điều kiện, hẹn một việc chạy ngầm sau 5 giây
2. Vẽ và gắnTrong WP-Cron, ngoài phiên của người viếtGọi API, lưu tệp, tạo tệp đính kèm, gắn hình đại diện
3. Thử lạiKhi gặp 503 hoặc lỗi mạngHẹn lại theo Retry-After, tối đa 5 lần

Người viết bấm Đăng xong là xong. Hình đại diện xuất hiện sau, thường trong vòng một phút với hạng Plus.

Vì sao cần một trường mô tả cảnh riêng

Có thể bạn nghĩ: lấy luôn tiêu đề bài làm câu lệnh vẽ. Có hai lý do không nên:

  1. API không tự dịch. Trang web của AI Hình Ảnh có bước chuyển mô tả tiếng Việt thành câu lệnh vẽ tiếng Anh, còn API thì đưa thẳng nội dung prompt tới máy vẽ. Tiêu đề "10 quán bún chả ngon ở Hà Nội" gửi nguyên văn sẽ cho kết quả kém sát.
  2. Tiêu đề không phải cảnh. "Cách bảo quản rau thơm được lâu" không nói máy vẽ cần vẽ gì, góc nào, ánh sáng ra sao.

Vì vậy plugin đọc một trường tuỳ biến tên ahn_canh: một câu tiếng Anh 15–30 từ tả cảnh. Bài nào không có trường này thì plugin bỏ qua, không vẽ bừa. Ví dụ cho bài về rau thơm:

Fresh Vietnamese herbs wrapped in damp paper towel inside a glass container on a kitchen counter, soft morning light, close-up, shallow depth of field

Người viết không quen tiếng Anh có thể gõ mô tả tiếng Việt trên ô vẽ một lần, xem dòng "Câu lệnh vẽ" dưới kết quả, rồi chép vào trường. Làm vài lần là quen khuôn câu.

Mã plugin

Đặt khoá trong wp-config.php, phía trên dòng "That's all, stop editing":

```php
define('AHN_KEY', 'ahn_XXXX');
```

Tạo tệp wp-content/mu-plugins/ahn-hinh-dau-bai.php (thư mục mu-plugins tự nạp, không cần bật trong trang quản trị; chưa có thì tạo):

```php
<?php
/**

  • Plugin Name: AI Hình Ảnh - hình đầu bài tự động
  • Description: Bài có trường ahn_canh mà chưa có hình đại diện thì vẽ bằng API sau khi đăng.

*/
if (!defined('ABSPATH')) exit;

const AHN_URL = 'https://aihinhanh.com/v1/images/generations';

add_action('transition_post_status', function ($moi, $cu, $post) {
if ($moi !== 'publish' || $cu === 'publish' || $post->post_type !== 'post') return;
if (has_post_thumbnail($post) || !get_post_meta($post->ID, 'ahn_canh', true)) return;
if (!wp_next_scheduled('ahn_ve_dau_bai', [$post->ID])) {
wp_schedule_single_event(time() + 5, 'ahn_ve_dau_bai', [$post->ID]);
}
}, 10, 3);

add_action('ahn_ve_dau_bai', 'ahn_ve_dau_bai');

function ahn_ve_dau_bai($post_id) {
$post = get_post($post_id);
if (!$post || has_post_thumbnail($post_id)) return;
$canh = trim((string) get_post_meta($post_id, 'ahn_canh', true));
if ($canh === '' || !defined('AHN_KEY')) return;
@set_time_limit(180);

$res = wp_remote_post(AHN_URL, [
'timeout' => 120,
'headers' => [
'Authorization' => 'Bearer ' . AHN_KEY,
'Content-Type' => 'application/json',
],
'body' => wp_json_encode([
'model' => get_post_meta($post_id, 'ahn_hang', true) ?: 'plus',
'prompt' => $canh . ', realistic editorial photo, no text, no logo',
'size' => '1536x1024',
'n' => 1,
'output_format' => 'webp',
]),
]);

if (is_wp_error($res)) { ahn_hen_lai($post_id, $res->get_error_message(), 120); return; }
$code = (int) wp_remote_retrieve_response_code($res);
$json = json_decode(wp_remote_retrieve_body($res), true);
if ($code === 503 || $code >= 500) {
$sau = (int) wp_remote_retrieve_header($res, 'retry-after') ?: 60;
ahn_hen_lai($post_id, "$code: " . ($json['error']['message'] ?? ''), $sau);
return;
}
if ($code !== 200 || empty($json['data'][0]['b64_json'])) {
update_post_meta($post_id, 'ahn_loi', "$code: " . ($json['error']['message'] ?? 'không rõ'));
return; // 400, 401, 402: không thử lại
}

$ten = sanitize_title($post->post_name ?: $post->post_title) . '-' . gmdate('ymd-His') . '.webp';
$up = wp_upload_bits($ten, null, base64_decode($json['data'][0]['b64_json']));
if (!empty($up['error'])) { update_post_meta($post_id, 'ahn_loi', $up['error']); return; }

require_once ABSPATH . 'wp-admin/includes/image.php';
$att = wp_insert_attachment([
'post_mime_type' => 'image/webp',
'post_title' => $post->post_title,
'post_status' => 'inherit',
], $up['file'], $post_id);
wp_update_attachment_metadata($att, wp_generate_attachment_metadata($att, $up['file']));

$alt = trim((string) get_post_meta($post_id, 'ahn_alt', true)) ?: $post->post_title;
update_post_meta($att, '_wp_attachment_image_alt', $alt);
update_post_meta($att, 'ahn_cau_lenh', $canh);
set_post_thumbnail($post_id, $att);
delete_post_meta($post_id, 'ahn_loi');
}

function ahn_hen_lai($post_id, $loi, $sau) {
$lan = (int) get_post_meta($post_id, 'ahn_lan', true) + 1;
update_post_meta($post_id, 'ahn_lan', $lan);
update_post_meta($post_id, 'ahn_loi', "lần $lan: $loi");
if ($lan <= 5) {
wp_schedule_single_event(time() + $sau + 30 * $lan, 'ahn_ve_dau_bai', [$post_id]);
}
}
```

Giải thích những chỗ quan trọng

transition_post_status thay vì save_post. save_post chạy mỗi lần lưu nháp, mỗi lần sửa chính tả. Chỉ cần vẽ đúng một lần khi bài từ trạng thái khác chuyển sang "đã đăng". Bài hẹn giờ cũng đi qua sự kiện này khi tới giờ đăng.

has_post_thumbnail kiểm hai lần. Một lần lúc hẹn, một lần lúc chạy. Nếu trong 5 giây đó biên tập viên kịp chọn hình thủ công, plugin không đè lên.

Hậu tố no text, no logo. Hình đầu bài hay bị máy vẽ thêm chữ vô nghĩa trên biển hiệu, bao bì. Gắn sẵn hậu tố này giảm hẳn chuyện đó. Chữ tiêu đề nếu cần đặt trên hình thì để giao diện trang lo.

Khổ 1536x1024. Tỉ lệ 3:2 hợp với hầu hết giao diện WordPress và cắt sang 16:9 cho Facebook vẫn đẹp. Muốn khổ màn rộng hẳn thì đổi 1664x928.

Trường ahn_hang. Mặc định Plus (500 điểm mỗi hình ảnh). Bài chân dung, thời trang thì người viết gõ pro vào trường này; cảnh nhiều người, cần bàn tay chuẩn thì max.

Thẻ alt. Lấy từ trường ahn_alt nếu có, không thì dùng tiêu đề bài. Alt tốt nhất là một câu tiếng Việt tả đúng hình ảnh, không nhồi từ khoá. Xem thêm bài lưu tệp, đặt tên, nén webp, thẻ alt.

Câu lệnh lưu kèm tệp đính kèm. Trường ahn_cau_lenh trên tệp giúp sau này biết hình ảnh vẽ từ câu nào, cần vẽ lại thì có sẵn.

Bật trường tuỳ biến trong trình soạn thảo

Trình soạn thảo khối của WordPress ẩn bảng trường tuỳ biến theo mặc định. Mở menu ba chấm ở góc phải, vào phần Tuỳ chọn, bật mục trường tuỳ biến (Custom fields), trình soạn thảo tải lại. Bảng hiện ở cuối trang soạn bài: thêm ahn_canh, ahn_alt, ahn_hang một lần, các bài sau chọn từ danh sách.

Lỗi hay gặp khi chạy thật

Triệu chứngNguyên nhânCách sửa
Đăng xong, mãi không có hìnhWP-Cron chỉ chạy khi có người vào trang; trang ít khách thì việc nằm chờĐặt cron thật trên máy chủ gọi wp-cron.php mỗi 5 phút
Trường ahn_loi ghi lỗi hết giờMáy chủ thuê giới hạn thời gian chạy PHP 30 giây, set_time_limit không có tác dụngChạy WP-Cron bằng dòng lệnh (php wp-cron.php) qua cron của máy chủ
Hình đại diện có nhưng không có bản thu nhỏThư viện GD trên máy chủ không hỗ trợ webpĐổi output_format sang jpeg và đuôi tệp .jpg, hoặc nhờ nhà cung cấp bật webp
401 trong ahn_loiThiếu hoặc sai AHN_KEY trong wp-config.phpKiểm tra khoá, khoá có đang bật ở trang khoá API
402 trong ahn_loiVí hết điểmNạp điểm; các bài đã lỗi phải hẹn lại bằng tay
Vẽ hai lần cho một bàiHai plugin cùng xử lý hình đại diệnTắt plugin hình đại diện tự động khác

Dòng thứ hai đáng nói thêm. Trên nhiều gói máy chủ thuê, PHP bị giới hạn 30 giây cho mỗi yêu cầu web, kể cả yêu cầu WP-Cron gọi ngầm. Lượt vẽ hạng Plus thường xong trong khoảng 10 giây khi máy rảnh, nhưng lúc bận có thể lâu hơn nhiều. Chạy WP-Cron bằng dòng lệnh (DISABLE_WP_CRON trong wp-config.php cộng một dòng cron của máy chủ) vừa tránh giới hạn thời gian vừa không làm chậm lượt xem của khách.

Chi phí cho một trang tin

Ba bài mỗi ngày, một hình ảnh Plus mỗi bài: 3 × 500 = 1.500 điểm mỗi ngày, khoảng 45.000 điểm mỗi tháng. Nếu một phần ba số bài cần hạng Pro cho chân dung, chi phí tháng khoảng 60.000 điểm. Ví điểm chung với các dịch vụ khác của hệ AI Đỉnh; giá API bằng giá web, xem ở bảng giá.

Mở rộng

  • Vẽ lại theo yêu cầu: thêm một nút nhỏ trong cột danh sách bài, gỡ hình đại diện cũ rồi gọi ahn_ve_dau_bai ngay.
  • Chọn từ hai hình ảnh: gửi n: 2, lưu cả hai vào thư viện, gắn hình đầu, để biên tập viên đổi nếu thích hình thứ hai. Chi phí gấp đôi.
  • Bài cũ chưa có hình: viết lệnh WP-CLI duyệt các bài có ahn_canh mà chưa có hình đại diện, hẹn việc cho từng bài cách nhau một phút.

Muốn xử lý lỗi kỹ hơn, xem bài xử lý lỗi 503 và Retry-After.

Hỏi đáp nhanh

Có thể dùng luôn tiêu đề bài làm câu lệnh vẽ không?
Được nhưng kết quả kém. API không tự dịch tiếng Việt và tiêu đề thường không tả cảnh. Một câu tiếng Anh 15 đến 30 từ nói rõ cái gì, ở đâu, ánh sáng, góc máy cho hình ảnh đúng ý hơn nhiều.
Vì sao không vẽ ngay khi bấm Đăng?
Mỗi lượt vẽ có thể mất tới khoảng 90 giây khi máy bận, người viết sẽ phải chờ và máy chủ thuê có thể cắt ngang yêu cầu. Hẹn việc chạy ngầm qua WP-Cron giúp bấm Đăng xong ngay, hình đại diện đến sau.
Trang ít khách thì WP-Cron có chạy không?
WP-Cron chỉ chạy khi có lượt truy cập, nên trang vắng có thể chờ lâu. Đặt cron thật trên máy chủ gọi wp-cron.php mỗi vài phút để việc chạy đúng giờ.
Máy chủ không hỗ trợ webp thì làm sao?
Đổi output_format thành jpeg và đuôi tệp thành .jpg trong mã. Hình đại diện vẫn chạy bình thường, chỉ nặng hơn một chút.
Bài nào không muốn vẽ hình tự động thì làm thế nào?
Không điền trường ahn_canh, hoặc chọn hình đại diện thủ công trước khi đăng. Plugin chỉ vẽ cho bài có trường mô tả cảnh và chưa có hình đại diện.
Tạo hình ảnh bằng AI từ mô tả tiếng ViệtGõ mô tả tiếng Việt, chọn hạng Plus, Pro hoặc Max — có hình ảnh trong vài giây.
Vẽ hình ảnh ngay

Đọc tiếp

Liên hệ AI Hình Ảnh
📞 Gọi 0918 832 283💬 Chat Zalo🟢 WhatsAppĐóng