Tới nội dung chính
hstation
Dịch vụDự ánVề tôiBlogThư viện nhạc

WordPress · 9 phút đọc · 2026-09-30

Viết bài tự động cho WordPress bằng ChatGPT: bản nháp tự động, người duyệt quyết định

Một file plugin thêm trang Công cụ, Viết nháp bằng ChatGPT: nhập chủ đề và dữ kiện, bài vào WordPress ở trạng thái Bản nháp. Kèm số đo từ một bài thật do GPT viết bản nền: 0 nguồn chết, nhưng vẫn sáu chỗ người duyệt phải sửa trước khi đăng.

Viết bài tự động cho WordPress ở đây nghĩa là: ChatGPT viết bản nháp, WordPress nhận bài ở trạng thái Bản nháp, và một người đọc lại, sửa, rồi mới bấm Đăng. Máy làm phần tốn thời gian; người giữ quyền quyết định bài nào được lên. Bài này cho bạn một file plugin làm đúng việc đó, và cho bạn xem một bản nháp GPT thật đã phải sửa những gì trước khi đăng.

Ranh giới cần nói trước: phần WordPress của plugin (trang nhập liệu, tạo bản nháp, lọc mã độc) mình đã chạy thật trên WordPress 7.1.2 ngày 30/09/2026, với một phản hồi giả lập theo đúng định dạng của OpenAI để không tốn tiền. Riêng lệnh gọi OpenAI trong plugin thì mình chưa chạy bằng khoá trả tiền. Số đo về chất lượng bản nháp GPT lấy từ dây chuyền viết bài thật của hstation, cũng chạy trên model của OpenAI.

Trước khi bắt đầu: bạn cần có gì

  • WordPress có tài khoản quản trị. Mình thử trên bản 7.1.2, giao diện tiếng Việt.
  • Quyền sửa file trên máy chủ, qua trình quản lý file của hosting hoặc FTP.
  • Khoá API OpenAI trong một project có trần chi tiêu. Cách lấy API key của ChatGPT và đặt trần chi tiêu có từng bước trong bài chatbot AI cho website, bước 1 và bước 2. Nếu đã làm theo bài đó, bạn tạo thêm một khoá thứ hai cho việc viết bài để theo dõi chi phí riêng.
  • Một bản sao lưu khôi phục được, vì bước 1 sửa wp-config.php.
  • Thời gian: khoảng 10 phút cho phần cài đặt.

Không cần: tài khoản n8n, máy chủ riêng, hay kiến thức lập trình.

Bước 1: Cất khoá vào wp-config.php

  1. Mở wp-config.php ở thư mục gốc WordPress, tải một bản về máy trước khi sửa.
  2. Dán dòng dưới đây ngay phía trên dòng /* That's all, stop editing! Happy publishing. */, thay phần trong ngoặc vuông bằng khoá của bạn:
php
define('VIET_NHAP_KHOA', '[dán khoá sk-... của bạn vào đây]');
  1. Lưu file, mở lại trang chủ. Xong khi: trang vẫn hiện bình thường. Nếu trang trắng: gần như chắc chắn thiếu dấu nháy hoặc dấu chấm phẩy ở dòng vừa dán; chép đè bản đã tải về rồi dán lại.

Bước 2: Cài plugin viết bài tự động cho WordPress

Đây là một plugin viết bài tự động bằng AI cho WordPress gói trong một file, tên hiển thị là "Viết nháp bằng ChatGPT".

  1. Trong wp-content/plugins/, tạo file viet-nhap-chatgpt.php và dán toàn bộ đoạn dưới:
php
<?php
/**
 * Plugin Name: Viết nháp bằng ChatGPT
 * Description: Trang Công cụ → Viết nháp bằng ChatGPT. Nhập chủ đề và dữ kiện, ChatGPT viết bài, bài vào WordPress ở trạng thái Bản nháp. Không bao giờ tự đăng.
 * Version: 1.0
 * Requires PHP: 8.0
 */

if (!defined('ABSPATH')) {
    exit;
}

// ==== PHẦN BẠN SỬA ====
const VIET_NHAP_MO_HINH = 'gpt-6.1-sol';
const VIET_NHAP_SUY_LUAN = 'low';       // gpt-6.1-sol nhận low, medium, high... KHÔNG nhận none
const VIET_NHAP_TOI_DA_TOKEN = 8000;    // trần token trả về, tính cả phần suy luận
// Khoá API đặt trong wp-config.php: define('VIET_NHAP_KHOA', 'sk-...');
// ==== HẾT PHẦN SỬA ====

add_action('admin_menu', function () {
    add_management_page('Viết nháp bằng ChatGPT', 'Viết nháp bằng ChatGPT', 'edit_posts', 'viet-nhap-chatgpt', 'viet_nhap_trang');
});

function viet_nhap_loi_nhac(string $chu_de, string $du_kien, int $so_chu): string
{
    return "Viết một bài blog tiếng Việt cho website.\n"
        . "Chủ đề: $chu_de\n\n"
        . "Thông tin có thật, chỉ được dùng những thông tin này:\n$du_kien\n\n"
        . "Yêu cầu:\n"
        . "- Dài khoảng $so_chu chữ.\n"
        . "- Chia 3 đến 5 mục, mỗi mục có tiêu đề.\n"
        . "- Không tự thêm con số, khuyến mãi, cam kết, trích dẫn, tên người hay đường dẫn nào ngoài thông tin trên.\n"
        . "- Chỗ nào cần thông tin mà phần trên không có thì ghi [CẦN BỔ SUNG: ...] để người duyệt tự điền.\n"
        . "- Xưng \"mình\", gọi người đọc là \"bạn\". Không dùng biểu tượng cảm xúc.\n"
        . "Trả về đúng hai phần: dòng đầu là tiêu đề bài, không có dấu #. Từ dòng thứ hai là thân bài bằng HTML,"
        . " chỉ dùng các thẻ h2, p, ul, ol, li, strong, em.";
}

function viet_nhap_goi_chatgpt(string $loi_nhac)
{
    if (!defined('VIET_NHAP_KHOA') || VIET_NHAP_KHOA === '') {
        return new WP_Error('thieu_khoa', 'Chưa có khoá API: thêm define(\'VIET_NHAP_KHOA\', \'sk-...\'); vào wp-config.php.');
    }
    $tra = wp_remote_post('https://api.openai.com/v1/chat/completions', [
        'timeout' => 180,
        'headers' => ['Content-Type' => 'application/json', 'Authorization' => 'Bearer ' . VIET_NHAP_KHOA],
        'body' => wp_json_encode([
            'model' => VIET_NHAP_MO_HINH,
            'reasoning_effort' => VIET_NHAP_SUY_LUAN,
            'max_completion_tokens' => VIET_NHAP_TOI_DA_TOKEN,
            'messages' => [['role' => 'user', 'content' => $loi_nhac]],
        ]),
    ]);
    if (is_wp_error($tra)) {
        return new WP_Error('mang', 'Chưa gọi được OpenAI: ' . $tra->get_error_message());
    }
    $ma = (int) wp_remote_retrieve_response_code($tra);
    $json = json_decode(wp_remote_retrieve_body($tra), true);
    if ($ma !== 200) {
        $ma_loi = (string) ($json['error']['code'] ?? $json['error']['type'] ?? 'khong_ro');
        return new WP_Error('openai', "OpenAI trả lỗi $ma ($ma_loi).");
    }
    $noi_dung = trim((string) ($json['choices'][0]['message']['content'] ?? ''));
    if ($noi_dung === '') {
        return new WP_Error('rong', 'OpenAI trả về rỗng. Tăng VIET_NHAP_TOI_DA_TOKEN rồi thử lại.');
    }
    return ['noi_dung' => $noi_dung, 'usage' => $json['usage'] ?? []];
}

function viet_nhap_trang()
{
    if (!current_user_can('edit_posts')) {
        wp_die('Bạn không có quyền dùng trang này.');
    }
    $bao = '';
    $chu_de = $du_kien = '';
    $so_chu = 800;
    if (isset($_POST['viet_nhap_gui'])) {
        check_admin_referer('viet_nhap');
        @set_time_limit(240); // viết bài dài có thể mất vài phút
        $chu_de = sanitize_text_field(wp_unslash($_POST['chu_de'] ?? ''));
        $du_kien = sanitize_textarea_field(wp_unslash($_POST['du_kien'] ?? ''));
        $so_chu = max(300, min(2000, (int) ($_POST['so_chu'] ?? 800)));
        if ($chu_de === '' || $du_kien === '') {
            $bao = '<div class="notice notice-error"><p>Cần nhập cả chủ đề và dữ kiện.</p></div>';
        } else {
            $kq = viet_nhap_goi_chatgpt(viet_nhap_loi_nhac($chu_de, $du_kien, $so_chu));
            if (is_wp_error($kq)) {
                $bao = '<div class="notice notice-error"><p>' . esc_html($kq->get_error_message()) . '</p></div>';
            } else {
                $dong = preg_split('/\R/', $kq['noi_dung'], 2);
                $tieu_de = trim(wp_strip_all_tags($dong[0] ?? $chu_de));
                $than = wp_kses_post($dong[1] ?? '');
                $id = wp_insert_post([
                    'post_title' => $tieu_de !== '' ? $tieu_de : $chu_de,
                    'post_content' => $than,
                    'post_status' => 'draft', // luôn là bản nháp, người duyệt mới bấm Đăng
                    'post_author' => get_current_user_id(),
                ], true);
                if (is_wp_error($id)) {
                    $bao = '<div class="notice notice-error"><p>Không tạo được bản nháp: ' . esc_html($id->get_error_message()) . '</p></div>';
                } else {
                    $token = (int) ($kq['usage']['total_tokens'] ?? 0);
                    $can_bo_sung = substr_count($than, 'CẦN BỔ SUNG');
                    $bao = '<div class="notice notice-success"><p>Đã tạo bản nháp: <a href="' . esc_url(get_edit_post_link($id)) . '">'
                        . esc_html(get_the_title($id)) . '</a>. Tổng token: ' . $token . '. Chỗ cần bổ sung: ' . $can_bo_sung . '.</p></div>';
                }
            }
        }
    }
    ?>
    <div class="wrap">
        <h1>Viết nháp bằng ChatGPT</h1>
        <?php echo $bao; ?>
        <p>Bài tạo ra luôn ở trạng thái <strong>Bản nháp</strong>. Đọc lại, sửa, rồi mới bấm Đăng.</p>
        <form method="post">
            <?php wp_nonce_field('viet_nhap'); ?>
            <table class="form-table" role="presentation">
                <tr><th scope="row"><label for="chu_de">Chủ đề</label></th>
                    <td><input name="chu_de" id="chu_de" type="text" class="regular-text" value="<?php echo esc_attr($chu_de); ?>" required></td></tr>
                <tr><th scope="row"><label for="du_kien">Dữ kiện có thật</label></th>
                    <td><textarea name="du_kien" id="du_kien" rows="8" class="large-text" required><?php echo esc_textarea($du_kien); ?></textarea>
                    <p class="description">Giá, thông số, chính sách... Bài chỉ được dùng những gì ghi ở đây.</p></td></tr>
                <tr><th scope="row"><label for="so_chu">Số chữ</label></th>
                    <td><input name="so_chu" id="so_chu" type="number" min="300" max="2000" value="<?php echo (int) $so_chu; ?>"></td></tr>
            </table>
            <?php submit_button('Viết bản nháp', 'primary', 'viet_nhap_gui'); ?>
        </form>
    </div>
    <?php
}
  1. Vào Plugin → Plugin đã cài đặt, bấm Kích hoạt dưới dòng "Viết nháp bằng ChatGPT". Xong khi: menu Công cụ có thêm mục Viết nháp bằng ChatGPT.

Ba con số trong phần sửa là mức mình đề xuất để bắt đầu. Model đặt sẵn là gpt-6.1-sol, loại mà trang model của OpenAI xếp vào nhóm cân bằng giữa chất lượng và giá, hợp với việc viết bài dài hơn là trả lời chat. Có hai chỗ dễ sai nếu bạn chép từ plugin chatbot sang:

  • gpt-6.1-sol không nhận reasoning_effort bằng none, chỉ nhận từ low trở lên (trang model). Plugin đặt low.
  • Trần max_completion_tokens tính cả phần suy luận của model. Đặt thấp quá thì bài bị cắt hoặc trả về rỗng; plugin đặt 8.000.

Bước 3: Viết bản nháp đầu tiên

  1. Vào Công cụ → Viết nháp bằng ChatGPT.
  2. Ô Chủ đề: một câu nói bài viết về gì, ví dụ "Cách chọn size áo sơ mi lụa".
  3. Ô Dữ kiện có thật: mọi con số, giá, thông số, chính sách mà bài được phép nói. Mỗi dòng một ý. Đây là ô quan trọng nhất: thứ gì không có ở đây, bài phải ghi [CẦN BỔ SUNG: ...] thay vì tự bịa.
  4. Ô Số chữ: để 800 cho lần đầu.
  5. Bấm Viết bản nháp, chờ. Viết bài dài có thể mất một hai phút.
Ảnh chụp trang Công cụ, Viết nháp bằng ChatGPT trong WordPress 7.1.2 tiếng Việt: ô Chủ đề điền "Cách chọn size áo sơ mi lụa", ô Dữ kiện có thật điền bốn dòng gồm 4 size S, M, L, XL, vòng ngực từng size, phom rộng nhẹ, và đổi size trong 7 ngày; ô Số chữ để 800; nút Viết bản nháp màu xanh.
Ảnh chụp trang Công cụ, Viết nháp bằng ChatGPT trong WordPress 7.1.2 tiếng Việt: ô Chủ đề điền "Cách chọn size áo sơ mi lụa", ô Dữ kiện có thật điền bốn dòng gồm 4 size S, M, L, XL, vòng ngực từng size, phom rộng nhẹ, và đổi size trong 7 ngày; ô Số chữ để 800; nút Viết bản nháp màu xanh.

Xong khi: hiện thông báo xanh "Đã tạo bản nháp: [tiêu đề]", kèm tổng token và số chỗ cần bổ sung. Bấm vào tiêu đề để mở bản nháp.

Khi mình chạy thử đường này bằng phản hồi giả lập: bản nháp được tạo đúng ở trạng thái Bản nháp; một thẻ script cố tình nhét vào phản hồi đã bị WordPress lọc bỏ, còn tiêu đề mục và đoạn văn vẫn giữ; số chỗ [CẦN BỔ SUNG] được đếm đúng.

Nếu hỏng, đọc dòng thông báo đỏ:

  • "Chưa có khoá API...": bước 1 chưa đúng, tên hằng số phải là VIET_NHAP_KHOA. Chữ bạn đã nhập vẫn được giữ lại trong ô, không phải gõ lại.
  • "OpenAI trả lỗi 401 (…)": khoá sai hoặc đã bị xoá.
  • "OpenAI trả lỗi 429 (…)": hết tiền, chạm trần chi tiêu, hoặc gọi quá nhanh.
  • "OpenAI trả về rỗng": tăng VIET_NHAP_TOI_DA_TOKEN rồi thử lại.
  • Trang báo lỗi hết thời gian chờ: hosting cắt các yêu cầu chạy lâu. Giảm số chữ xuống 500, hoặc hỏi nhà cung cấp hosting có cho tăng thời gian chạy PHP không.
Ảnh chụp cùng trang khi chưa cài khoá API: dải thông báo đỏ ghi "Chưa có khoá API: thêm define('VIET_NHAP_KHOA', 'sk-...'); vào wp-config.php", phía dưới là biểu mẫu với chủ đề và dữ kiện vẫn được giữ nguyên.
Ảnh chụp cùng trang khi chưa cài khoá API: dải thông báo đỏ ghi "Chưa có khoá API: thêm define('VIET_NHAP_KHOA', 'sk-...'); vào wp-config.php", phía dưới là biểu mẫu với chủ đề và dữ kiện vẫn được giữ nguyên.

Bản nháp GPT sai ở đâu: số đo từ một bài thật

Bài chatbot AI cho website trên hstation được dây chuyền viết bài chạy gpt-6.1-sol viết bản nền. Dây chuyền này làm kỹ hơn plugin ở trên: nó tra web, ghi nguồn cho từng dữ kiện, và gọi thử từng đường dẫn. Nhật ký lượt chạy đó:

  • 146.835 token gửi vào, 22.604 token nhận về, mất 7 phút 24 giây.
  • 30 dữ kiện, mỗi dữ kiện kèm đường dẫn nguồn: 23 mở được, 7 trang chặn máy phải tự mở bằng trình duyệt, 0 đường dẫn không tồn tại.
  • Ước tính theo giá gpt-6.1-sol (2 USD mỗi triệu token vào, 10 USD mỗi triệu token ra): khoảng 0,52 USD cho bài đó. Con số thật thấp hơn một chút vì khâu viết thẻ tìm kiếm chạy model rẻ hơn.

Nguồn thì ổn. Nhưng bản nền chưa làm theo được. Đây là sáu chỗ mình phải sửa trước khi đăng:

Biểu đồ số đo của lượt GPT viết bản nền bài chatbot AI cho website: 146.835 token gửi vào, 22.604 token nhận về, 7 phút 24 giây, khoảng 0,52 USD; 30 dữ kiện có nguồn, trong đó 23 mở được và 7 chặn máy, 0 đường dẫn không tồn tại; và danh sách sáu chỗ người duyệt phải sửa: thiếu bước tạo khoá API, để trống 5 giới hạn trong mã mẫu, một đoạn nói chuyện nội bộ, tiêu đề mục gây hiểu sai, chọn model không phải loại OpenAI khuyên cho việc cần rẻ, và mã mẫu quá phức tạp.
Biểu đồ số đo của lượt GPT viết bản nền bài chatbot AI cho website: 146.835 token gửi vào, 22.604 token nhận về, 7 phút 24 giây, khoảng 0,52 USD; 30 dữ kiện có nguồn, trong đó 23 mở được và 7 chặn máy, 0 đường dẫn không tồn tại; và danh sách sáu chỗ người duyệt phải sửa: thiếu bước tạo khoá API, để trống 5 giới hạn trong mã mẫu, một đoạn nói chuyện nội bộ, tiêu đề mục gây hiểu sai, chọn model không phải loại OpenAI khuyên cho việc cần rẻ, và mã mẫu quá phức tạp.
  1. Thiếu hẳn một bước quan trọng. Bài hướng dẫn gắn ChatGPT mà không có bước tạo khoá API, dù chính sổ dữ kiện của dây chuyền có ghi đường tạo khoá.
  2. Bắt người đọc tự đoán. Mã mẫu để trống 5 giới hạn và dặn "điền số phù hợp", không gợi ý số nào.
  3. Lẫn chuyện nội bộ vào bài. Một đoạn kể "tư liệu biên tập có ghi nhận... liên kết ấy đang chết", trong khi chính lượt chạy đo ra 0 đường dẫn chết. Người đọc không cần đoạn đó, và nó còn sai.
  4. Tiêu đề gây hiểu sai. Một mục tên "Đào tạo Chatbot AI" trong khi bài không huấn luyện gì, chỉ để lọt một cụm từ khoá.
  5. Chọn model theo trí nhớ cũ. Mã mẫu dùng gpt-4.1-mini, trong khi trang model của OpenAI hiện khuyên gpt-6-luna cho việc cần rẻ và số lượng lớn.
  6. Phức tạp không cần thiết. Mã mẫu có câu lệnh SQL sửa thẳng bảng wp_options, còn khung chat lại không có giao diện.

Bản đăng dài 2.265 từ tính cả khối mã, so với 1.829 từ của bản nền; phần các bước gần như viết lại toàn bộ. Điểm chung của sáu lỗi: không lỗi nào là bịa số liệu. GPT hỏng ở chỗ bài không làm theo được, thứ mà máy kiểm nguồn không bắt được.

Duyệt bản nháp trước khi bấm Đăng

Mở bản nháp trong Bài viết → Tất cả bài viết, lọc Bản nháp, rồi đi qua từng việc:

  1. Tìm `[CẦN BỔ SUNG` bằng Ctrl+F. Điền số thật hoặc xoá câu đó. Không để lọt một chỗ nào.
  2. Đối chiếu mọi con số với ô dữ kiện. Số nào không có trong dữ kiện là số bịa, xoá đi.
  3. Nếu là bài hướng dẫn, tự làm lại từng bước. Bước nào bạn phải đoán, bước đó viết lại cho rõ: tên nút, đường dẫn menu, dấu hiệu đã xong.
  4. Đọc tiêu đề từng mục. Mục nào tiêu đề không khớp nội dung thì đổi tên hoặc gộp mục.
  5. Xoá những đoạn nói về chính việc viết bài, kiểu "bài này sẽ...", "như đã đề cập...".
  6. Chọn ảnh, chuyên mục, rồi mới bấm Đăng.

Nếu bạn viết bài chuẩn SEO, bài viết bài chuẩn SEO bằng AI có 24 lỗi hay gặp để soi thêm.

Mỗi bản nháp tốn bao nhiêu

Viết bài tự động cho WordPress theo cách này rẻ hơn nhiều so với dây chuyền ở trên, vì plugin gọi OpenAI đúng một lần mỗi bản nháp, không tra web. Ước tính của mình, không phải hoá đơn: nếu lời nhắc kèm dữ kiện khoảng 1.000 token và bài trả về khoảng 3.000 token tính cả phần suy luận, thì với gpt-6.1-sol là 0,002 + 0,03 = khoảng 0,03 USD một bản nháp. Số token thật hiện ngay trong thông báo xanh sau mỗi lần tạo; nhân với giá trên trang model là ra số thật của bạn.

Viết từ bên ngoài WordPress: mật khẩu ứng dụng

Nếu bạn muốn viết bài tự động trên WordPress với n8n hay một đoạn mã chạy định kỳ, thay vì bấm trong trang quản trị, dùng mật khẩu ứng dụng WordPress:

  1. Vào Tài khoản → Hồ sơ, kéo xuống mục Mật khẩu ứng dụng.
  2. Ô Tên mật khẩu ứng dụng mới, gõ ví dụ viet-nhap, bấm Thêm mật khẩu ứng dụng. Chép chuỗi hiện ra.
  3. Công cụ bên ngoài gửi bài tới đường /wp-json/wp/v2/posts, xác thực bằng tên đăng nhập kèm mật khẩu ứng dụng, và luôn gửi kèm `"status": "draft"`.

Mình đã thử đường này ngày 30/09/2026: 6 lần gửi liên tiếp, lần nào WordPress cũng trả mã 201 và tạo đúng bản nháp. Cách nối đường này bằng n8n có ở bài tự động đăng bài lên WordPress bằng n8n.

Kiểm lại trước khi dùng thật

  • Khoá nằm trong wp-config.php, không có trong file plugin.
  • Project chứa khoá có trần chi tiêu đang bật.
  • Tạo thử một bản nháp: thông báo xanh hiện ra, bài nằm trong danh sách với nhãn Bản nháp, chưa ai ngoài site thấy được.
  • Bản nháp không còn chỗ [CẦN BỔ SUNG nào trước khi bấm Đăng.
  • Mọi con số trong bài đều có trong ô dữ kiện.

Những gì mình chưa kiểm

  • Gọi OpenAI bằng khoá trả tiền từ chính plugin này, nên chưa có số đo thời gian và số token thật cho một bản nháp.
  • Hosting chia sẻ với giới hạn thời gian chạy PHP chặt.
  • Viết song song nhiều bài, và viết bài dài hơn 2.000 chữ.