หากคุณเคยเสียเวลา 40 นาทีในการเขียนคำอธิบายสินค้า แต่ได้ผลลัพธ์ที่ไม่ค่อยน่าสนใจ คุณจะต้องชอบขั้นตอนการทำงานนี้: WooCommerce จะสร้างคำอธิบายแบบ "ยาว" และคำอธิบายแบบ "สั้น" จากชื่อสินค้า คุณสมบัติ และหมายเหตุทางธุรกิจเล็กน้อย — และคุณยังสามารถควบคุมการตรวจสอบความถูกต้องได้เอง
ความต้องการ / กรณีการใช้งาน
ในแคตตาล็อกของ WooCommerce การสร้างเนื้อหามักเป็นคอขวด ฉันเคยเห็นร้านค้าที่มีสินค้า 300 รายการอยู่ในสถานะ "รอดำเนินการ" เพียงเพราะขาดคำอธิบาย แม้ว่ารูปภาพและราคาจะพร้อมแล้วก็ตาม ผลที่ตามมาคือ SEO แย่ลง อัตราการแปลงลูกค้าลดลง และทีมงานต้องเลื่อนการเปิดตัวออกไป
AI มีประโยชน์ในที่นี้ในการสร้างร่างแรกที่มีความสอดคล้อง มีโครงสร้าง และมุ่งเน้นผลกำไร จากข้อมูลที่มีอยู่แล้ว WordPress : ชื่อเรื่อง หมวดหมู่ คุณลักษณะ แบรนด์ ขนาด วัสดุ ฯลฯ เป้าหมายไม่ใช่การใช้ระบบอัตโนมัติโดยไม่คิดไตร่ตรอง แต่เป็นการลดเวลาในการเขียนต่อผลิตภัณฑ์ ในขณะที่ยังคงรักษาการควบคุมด้านบรรณาธิการไว้
สุดท้ายแล้ว คุณจะรู้วิธีนำไปใช้:
- ปุ่ม “สร้างด้วย AI” ในหน้าแก้ไขสินค้า (ส่วนผู้ดูแลระบบ WooCommerce)
- การเรียกใช้ API ของ AI ผ่านทาง
wp_remote_post()(Sans SDK) พร้อมระบบจัดการเวลาหมดและข้อผิดพลาด - ใช้แคชเพียงหนึ่งครั้งต่อข้อมูลชั่วคราว เพื่อหลีกเลี่ยงการจ่ายค่าบริการสำหรับข้อมูลชุดเดียวกันซ้ำอีก
- การอัปเดตที่ปลอดภัยของ คำอธิบายโดยละเอียด et คำอธิบายโดยย่อ (ส่วนหนึ่ง) จากผลิตภัณฑ์
- ระบบจำกัดอัตราค่าบริการแบบง่ายๆ เพื่อหลีกเลี่ยงอัตราค่าบริการที่พุ่งสูงขึ้น (และบิลค่าบริการที่ไม่คาดคิด)
สรุปด่วน
- เราเพิ่มเมตาบ็อกซ์ของ WooCommerce พร้อมปุ่มที่เรียกใช้งานคำขอ AJAX สำหรับผู้ดูแลระบบ
- เซิร์ฟเวอร์จะสร้างข้อความแจ้งเตือนจากข้อมูลผลิตภัณฑ์ (คุณลักษณะ หมวดหมู่ ฯลฯ)
- การโทรด้วย AI
wp_remote_post()กำหนดเวลาหมดอายุสั้น จำกัดจำนวนครั้งในการลองใหม่ และบันทึกข้อผิดพลาด - ตอบกลับแบบสะอาดด้วย
wp_kses_post()ก่อนสอดใส่เข้าไปpost_contentetpost_excerpt. - ใช้ Transients API ในการแคชเพื่อหลีกเลี่ยงการสร้างแคชใหม่หากไม่มีอะไรเปลี่ยนแปลง
- คีย์ API ถูกจัดเก็บไว้แล้ว
wp-config.php(ไม่เคยเขียนโค้ดแบบตายตัว ไม่เคยเขียนในฝั่ง JavaScript)
ควรใช้ AI สำหรับเรื่องนั้นเมื่อใด
ใช้ AI เมื่อคุณมีข้อมูลปริมาณมาก โครงสร้างข้อมูลที่เชื่อถือได้ และต้องการความสม่ำเสมอ โดยทั่วไป:
- ร้านค้าหลายผู้ขาย โดยที่ข้อมูลจะเข้ามาในรูปแบบข้อมูลดิบ (CSV, ERP) ซึ่งมีข้อความน้อยมาก
- แคตตาล็อกที่มีความหลากหลาย (ขนาด/สี) ที่คุณต้องการคำอธิบายที่เป็นมาตรฐาน และจัดการความแตกต่างด้วยคุณลักษณะ
- SEO “พื้นฐาน” : สร้างข้อความที่สะอาดตา อ่านง่าย และมีโครงสร้างที่มั่นคง (ย่อหน้า รายการ) จากนั้นจึงปรับแต่งผลลัพธ์เชิงกลยุทธ์ให้ดียิ่งขึ้น
- ความเป็นสากล (เวอร์ชันขั้นสูง): สร้างเวอร์ชันภาษาอังกฤษ/เยอรมัน/สเปนจากฐานข้อมูลภาษาฝรั่งเศส โดยมีการตรวจสอบความถูกต้องโดยมนุษย์
ในสถานการณ์จริง สิ่งที่ได้ผลดีคือการสร้างผลิตภัณฑ์เมื่อมีการสร้างผลิตภัณฑ์นั้นขึ้นมา จากนั้นจึงสร้างใหม่เฉพาะเมื่อฟิลด์บางอย่างเปลี่ยนแปลง (คุณลักษณะ หมวดหมู่ แบรนด์) การแคชข้อมูลโดยใช้ "ลายนิ้วมือ" ของผลิตภัณฑ์จะช่วยได้มาก
เมื่อใดที่ไม่ควรใช้ AI
ควรหลีกเลี่ยงการใช้ AI หากวิธีการแบบดั้งเดิมมีความเสถียรกว่าหรือมีความเสี่ยงน้อยกว่า:
- คำอธิบายที่ถูกต้องตามกฎหมายอย่างเคร่งครัด (เครื่องสำอาง อาหารเสริม ยา): ความเสี่ยงต่อการเกิดภาพหลอนมีอยู่จริง ควรใช้เทมเพลต PHP ที่มีฟิลด์/แอตทริบิวต์ ACF หรือฐานข้อมูลที่ได้รับการตรวจสอบความถูกต้องตามกฎหมาย
- ผลิตภัณฑ์ที่ใช้เทคโนโลยีขั้นสูง แม้แต่ข้อผิดพลาดเพียงเล็กน้อยก็อาจส่งผลให้เกิดการส่งคืนสินค้าเพื่อขอรับบริการจากฝ่ายบริการลูกค้า (ความเข้ากันได้ มาตรฐาน) คุณยังสามารถใช้ AI ได้ แต่เฉพาะในข้อความแจ้งเตือนที่ล็อกไว้และมีการตรวจสอบความถูกต้องที่จำเป็นเท่านั้น
- เว็บไซต์ที่มีข้อจำกัดด้านต้นทุนอย่างเข้มงวดมาก หากคุณมีสินค้า 20,000 รายการ และสร้างรายการใหม่บ่อยครั้ง ค่าใช้จ่าย API จะเพิ่มขึ้นอย่างรวดเร็วหากคุณไม่ใช้การแคชและการประมวลผลแบบกลุ่ม
- เมื่อข้อมูลต้นทางของคุณไม่ดี (ชื่อเรื่องไม่สอดคล้องกัน คุณสมบัติว่างเปล่า) AI จะ "สร้าง" ข้อมูลขึ้นมาเพื่อเติมเต็มช่องว่าง ในกรณีนี้ ให้เริ่มต้นด้วยการทำความสะอาดแคตตาล็อก
รูปแบบที่ไม่พึงประสงค์ที่พบได้บ่อยคือ การเรียกใช้งานการสร้างหน้าเว็บทุกครั้งที่มีการบันทึกอัตโนมัติ คุณจะลงเอยด้วยการเรียกใช้ API หลายสิบครั้งสำหรับสินค้าชิ้นเดียว เนื่องจาก Gutenberg บันทึกอัตโนมัติ WooCommerce อัปเดตเมตาแท็ก และ hook ของคุณจะถูกเรียกใช้งานแบบต่อเนื่อง
ข้อกำหนดเบื้องต้น
ภายในเดือนเมษายน 2026 ตั้งเป้าหมายอย่างน้อยดังนี้:
- WordPress 6.9.4 (บริบทของคุณ) และ PHP ฮิต +.
- WooCommerce อัปเดตล่าสุด (เวอร์ชัน 2026) โค้ดด้านล่างนี้ใช้ API ที่เสถียรของ WordPress ไม่ใช่กลไกภายในที่ไม่เสถียรของ WooCommerce
- การเข้าถึง
wp-config.php(หรือตัวแปรสภาพแวดล้อม) เพื่อจัดเก็บคีย์ API
บันทึกคีย์ API (ในไฟล์ wp-config.php)
เพิ่มสิ่งนี้ลงใน wp-config.php (โดยหลักการแล้ว ควรใช้ระบบจัดการความลับของโฮสติ้งผู้ให้บริการของคุณ แต่การใช้ค่าคงที่ก็ถือเป็นพื้นฐานที่ดี)
/**
* Clé API OpenAI (exemple).
* Ne la commitez jamais dans Git. Ne la mettez jamais dans un plugin.
*/
define('BPCAB_OPENAI_API_KEY', 'sk-proj-...');
หากคุณต้องการใช้ตัวแปรสภาพแวดล้อม คุณสามารถทำได้ดังนี้:
define('BPCAB_OPENAI_API_KEY', getenv('BPCAB_OPENAI_API_KEY') ?: '');
เอกสารอ้างอิงอย่างเป็นทางการที่เป็นประโยชน์
- wp_remote_post() (แหล่งข้อมูลสำหรับนักพัฒนา WordPress)
- Nonces (WordPress)
- wp_kses_post() (การตรวจสอบความปลอดภัยของ HTML)
- API Transients
- JSON ใน PHP (php.net)
สถาปัตยกรรมโซลูชัน
ผังการไหล (แผนผังข้อความ):
การจัดการผลิตภัณฑ์ (ปุ่มสร้าง) → การจัดการ AJAX (nonce + ความสามารถ) → การดึงข้อมูลผลิตภัณฑ์ → การคำนวณแฮช → แคชชั่วคราว? → อย่างอื่น wp_remote_post() → API AI → การแยกวิเคราะห์ JSON → การตรวจสอบความปลอดภัย (
wp_kses_post()) → อัปเดตผลิตภัณฑ์ (เนื้อหา + บทคัดย่อ) → ส่งกลับ JSON ไปยังผู้ดูแลระบบ
เกิดอะไรขึ้นเบื้องหลัง
- ผู้ดูแลระบบ UI กล่องเมตาที่มีปุ่มและช่อง "หมายเหตุ" ที่เป็นตัวเลือก โค้ด JavaScript ไม่มีการใส่คีย์ API เลย
- จุดสิ้นสุด AJAX : รักษาความปลอดภัยด้วย nonce +
current_user_can('edit_product', $product_id). - รวดเร็ว สร้างขึ้นจากองค์ประกอบที่เชื่อถือได้ (แอตทริบิวต์ หมวดหมู่ แท็ก และราคาจาก WooCommerce หากต้องการ)
- แคช : ข้อมูลชั่วคราวที่สร้างขึ้นจากค่าแฮชของข้อมูล หากไม่มีการเปลี่ยนแปลงใดๆ ระบบจะส่งคืนคำอธิบายที่สร้างไว้แล้ว
- การรักษาสุขอนามัย AI สามารถส่งคืน HTML ได้ เฉพาะสิ่งที่ WordPress อนุญาตในโพสต์เท่านั้นที่จะได้รับอนุญาตผ่านทาง AI
wp_kses_post().
โค้ดฉบับสมบูรณ์ — ทีละขั้นตอน
ฉันแนะนำให้คุณเลือก หมู่-เสียบเข้าไป เพื่อป้องกันไม่ให้ธีมย่อยหรือปลั๊กอินโค้ดสั้นเสียหายระหว่างการอัปเดต ให้สร้าง: wp-content/mu-plugins/bpcab-ai-woo-descriptions.php.
1) บันทึกเมตาบ็อกซ์ในส่วนผู้ดูแลระบบผลิตภัณฑ์
เราใช้หน้าจอ productเมตาบ็อกซ์นี้ยังคงใช้งานได้ไม่ว่าคุณจะใช้ตัวสร้างเว็บไซต์ส่วนหน้าแบบใด (Divi/Elementor/Avada) เนื่องจากมีการดำเนินการในส่วนผู้ดูแลระบบของ WooCommerce
<?php
/**
* Plugin Name: BPCAB - IA descriptions produits WooCommerce
* Description: Génère des descriptions produits via IA depuis l'admin WooCommerce (WP 6.9.4+, PHP 8.1+).
* Version: 1.0.0
*/
if (!defined('ABSPATH')) {
exit;
}
add_action('add_meta_boxes', function () {
add_meta_box(
'bpcab_ai_product_desc',
'Descriptions IA',
'bpcab_render_ai_metabox',
'product',
'side',
'high'
);
});
function bpcab_render_ai_metabox(WP_Post $post): void {
$product_id = (int) $post->ID;
if (!current_user_can('edit_product', $product_id)) {
echo '<p>Vous n’avez pas les droits pour modifier ce produit.</p>';
return;
}
wp_nonce_field('bpcab_ai_generate_desc', 'bpcab_ai_nonce');
echo '<p>
<label for="bpcab_ai_notes"><strong>Notes internes (optionnel)</strong></label>
<textarea id="bpcab_ai_notes" style="width:100%;min-height:70px;" placeholder="Ex: ton premium, mentionner la garantie 2 ans, éviter les superlatifs..."></textarea>
</p>';
echo '<p>
<button type="button" class="button button-primary" id="bpcab-ai-generate" data-product-id="' . esc_attr((string) $product_id) . '">
Générer avec IA
</button>
</p>';
echo '<div id="bpcab-ai-status" style="margin-top:8px;"></div>';
}
2) โหลดสคริปต์ JavaScript เฉพาะในหน้าจอผลิตภัณฑ์เท่านั้น
ข้อผิดพลาดที่ผมเห็นบ่อยคือ การเรียกใช้สคริปต์ทุกที่ในแผงควบคุมผู้ดูแลระบบ วิธีนี้ทำให้ระบบทำงานช้าลงโดยไม่จำเป็น และอาจทำให้เกิดความขัดแย้งกับปลั๊กอินอื่นๆ ได้
add_action('admin_enqueue_scripts', function (string $hook_suffix) {
// Écrans typiques : post.php (édition), post-new.php (création)
if (!in_array($hook_suffix, ['post.php', 'post-new.php'], true)) {
return;
}
$screen = get_current_screen();
if (!$screen || $screen->post_type !== 'product') {
return;
}
wp_enqueue_script(
'bpcab-ai-woo-admin',
plugins_url('bpcab-ai-woo-admin.js', __FILE__),
['jquery'],
'1.0.0',
true
);
wp_localize_script('bpcab-ai-woo-admin', 'BPCAB_AI', [
'ajaxUrl' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('bpcab_ai_generate_desc'),
]);
});
ขั้นตอนต่อไปคือการสร้างไฟล์ wp-content/mu-plugins/bpcab-ai-woo-admin.jsใช่แล้ว ปลั๊กอิน mu สามารถโหลดไฟล์ JS แยกต่างหากได้ ตราบใดที่พาธถูกต้อง หากโครงสร้างพื้นฐานของคุณไม่อนุญาตให้ทำเช่นนั้น ให้ใส่ไฟล์ JS ไว้ในปลั๊กอินทั่วไป (ซึ่งมักจะง่ายกว่า)
(function ($) {
function setStatus(html) {
$('#bpcab-ai-status').html(html);
}
$(document).on('click', '#bpcab-ai-generate', function () {
var productId = $(this).data('product-id');
var notes = $('#bpcab_ai_notes').val() || '';
setStatus('<p>Génération en cours… (ne fermez pas cet onglet)</p>');
$.ajax({
url: BPCAB_AI.ajaxUrl,
method: 'POST',
dataType: 'json',
data: {
action: 'bpcab_ai_generate_product_desc',
nonce: BPCAB_AI.nonce,
product_id: productId,
notes: notes
}
})
.done(function (resp) {
if (!resp || !resp.success) {
var msg = (resp && resp.data && resp.data.message) ? resp.data.message : 'Erreur inconnue.';
setStatus('<p style="color:#b32d2e;"><strong>Échec:</strong> ' + msg + '</p>');
return;
}
setStatus(
'<p style="color:#1e7e34;"><strong>OK:</strong> Descriptions mises à jour.</p>' +
'<p>Astuce: cliquez sur “Mettre à jour” pour déclencher les hooks habituels de votre stack (cache, SEO, etc.).</p>'
);
})
.fail(function (xhr) {
setStatus('<p style="color:#b32d2e;"><strong>Erreur AJAX:</strong> vérifiez la console et vos logs PHP.</p>');
});
});
})(jQuery);
3) สร้างเอนด์พอยต์ AJAX (ด้านความปลอดภัยและการตรวจสอบความถูกต้อง)
เราตรวจสอบค่า nonce, สิทธิ์การเข้าถึง และรหัสผลิตภัณฑ์ และเราจะป้องกันการเรียกใช้งานหากไม่ได้กำหนดค่าคีย์ API ไว้
add_action('wp_ajax_bpcab_ai_generate_product_desc', function () {
// Vérification nonce
$nonce = isset($_POST['nonce']) ? sanitize_text_field((string) $_POST['nonce']) : '';
if (!wp_verify_nonce($nonce, 'bpcab_ai_generate_desc')) {
wp_send_json_error(['message' => 'Nonce invalide. Rechargez la page produit.'], 403);
}
$product_id = isset($_POST['product_id']) ? (int) $_POST['product_id'] : 0;
if ($product_id <= 0) {
wp_send_json_error(['message' => 'ID produit invalide.'], 400);
}
if (!current_user_can('edit_product', $product_id)) {
wp_send_json_error(['message' => 'Droits insuffisants.'], 403);
}
if (!defined('BPCAB_OPENAI_API_KEY') || !BPCAB_OPENAI_API_KEY) {
wp_send_json_error(['message' => 'Clé API manquante. Définissez BPCAB_OPENAI_API_KEY dans wp-config.php.'], 500);
}
$notes = isset($_POST['notes']) ? wp_kses_post((string) $_POST['notes']) : '';
$result = bpcab_ai_generate_and_update_product($product_id, $notes);
if (is_wp_error($result)) {
wp_send_json_error([
'message' => $result->get_error_message(),
'code' => $result->get_error_code(),
], 500);
}
wp_send_json_success(['updated' => true]);
});
4) ดึงข้อมูลผลิตภัณฑ์และสร้างข้อความแจ้งเตือน
เราใช้ WooCommerce หากมีให้บริการ มิเช่นนั้นเราจะแสดงข้อผิดพลาดที่ชัดเจน อย่าสับสนสิ่งนี้กับ hook save_post จนกว่าคุณจะทำให้กระบวนการทำงานคงที่แล้ว การใช้ AJAX จะคาดเดาได้ง่ายกว่า
function bpcab_ai_generate_and_update_product(int $product_id, string $notes = '') {
if (!function_exists('wc_get_product')) {
return new WP_Error('woocommerce_missing', 'WooCommerce ne semble pas actif.');
}
$product = wc_get_product($product_id);
if (!$product) {
return new WP_Error('product_missing', 'Produit introuvable.');
}
// Rate limiting basique (par produit + utilisateur) pour éviter les rafales.
$user_id = get_current_user_id();
$rl_key = 'bpcab_ai_rl_' . $user_id . '_' . $product_id;
if (get_transient($rl_key)) {
return new WP_Error('rate_limited', 'Vous générez trop vite. Attendez 30 secondes et réessayez.');
}
set_transient($rl_key, 1, 30);
$payload = bpcab_build_product_payload_for_prompt($product);
// Empreinte: si les données n'ont pas changé, on peut servir depuis cache.
$fingerprint = hash('sha256', wp_json_encode([
'payload' => $payload,
'notes' => $notes,
'v' => '1.0.0', // incrémentez si vous changez la logique de prompt
]));
$cache_key = 'bpcab_ai_desc_' . $product_id . '_' . substr($fingerprint, 0, 12);
$cached = get_transient($cache_key);
if (is_array($cached) && isset($cached['long'], $cached['short'])) {
return bpcab_update_product_descriptions($product_id, $cached['long'], $cached['short']);
}
$prompt = bpcab_build_prompt($payload, $notes);
$ai = bpcab_call_openai_responses_api($prompt);
if (is_wp_error($ai)) {
return $ai;
}
// Sanitation: on autorise un HTML "post" standard, pas de scripts, pas d'iframes.
$long = wp_kses_post($ai['long'] ?? '');
$short = wp_kses_post($ai['short'] ?? '');
// Fallback si l'IA renvoie vide (ça arrive avec des prompts trop stricts).
if (mb_strlen(wp_strip_all_tags($long)) < 80) {
return new WP_Error('ai_empty', 'La réponse IA est trop courte ou vide. Vérifiez vos données produit et le prompt.');
}
if (mb_strlen(wp_strip_all_tags($short)) < 30) {
$short = wp_trim_words(wp_strip_all_tags($long), 35, '…');
}
// Cache 30 jours (vous pouvez réduire si votre catalogue change souvent).
set_transient($cache_key, ['long' => $long, 'short' => $short], 30 * DAY_IN_SECONDS);
return bpcab_update_product_descriptions($product_id, $long, $short);
}
function bpcab_build_product_payload_for_prompt(WC_Product $product): array {
$product_id = $product->get_id();
$cats = wp_get_post_terms($product_id, 'product_cat', ['fields' => 'names']);
$tags = wp_get_post_terms($product_id, 'product_tag', ['fields' => 'names']);
// Attributs WooCommerce (pa_*) et attributs custom.
$attributes_out = [];
foreach ($product->get_attributes() as $attr) {
if ($attr->is_taxonomy()) {
$taxonomy = $attr->get_name();
$label = wc_attribute_label($taxonomy);
$terms = wp_get_post_terms($product_id, $taxonomy, ['fields' => 'names']);
$attributes_out[] = [
'label' => $label,
'values' => array_values(array_filter(array_map('sanitize_text_field', $terms))),
];
} else {
$attributes_out[] = [
'label' => sanitize_text_field($attr->get_name()),
'values' => array_values(array_filter(array_map('sanitize_text_field', $attr->get_options()))),
];
}
}
$sku = (string) $product->get_sku();
$price = $product->get_price();
$regular = $product->get_regular_price();
$sale = $product->get_sale_price();
return [
'title' => sanitize_text_field($product->get_name()),
'sku' => sanitize_text_field($sku),
'categories' => array_values(array_filter(array_map('sanitize_text_field', (array) $cats))),
'tags' => array_values(array_filter(array_map('sanitize_text_field', (array) $tags))),
'attributes' => $attributes_out,
'price' => $price !== '' ? (string) $price : '',
'regular_price' => $regular !== '' ? (string) $regular : '',
'sale_price' => $sale !== '' ? (string) $sale : '',
'short_description_existing' => wp_strip_all_tags((string) $product->get_short_description()),
'description_existing' => wp_strip_all_tags((string) $product->get_description()),
];
}
function bpcab_build_prompt(array $payload, string $notes = ''): string {
$attrs_lines = [];
foreach (($payload['attributes'] ?? []) as $attr) {
$label = $attr['label'] ?? '';
$values = $attr['values'] ?? [];
if (!$label || empty($values)) {
continue;
}
$attrs_lines[] = '- ' . $label . ' : ' . implode(', ', $values);
}
$notes_clean = trim(wp_strip_all_tags($notes));
// Prompt orienté e-commerce: bénéfices, usage, contraintes, pas de promesses non vérifiées.
$prompt = "Vous êtes un rédacteur e-commerce senior. Rédigez pour WooCommerce une description produit en FR.nn";
$prompt .= "Règles STRICTES:n";
$prompt .= "1) N'inventez aucune caractéristique non fournie.n";
$prompt .= "2) Pas de superlatifs gratuits ("le meilleur", "incroyable").n";
$prompt .= "3) Style clair, concret, orienté bénéfices et usages.n";
$prompt .= "4) HTML autorisé: <p>, <ul>, <li>, <strong>, <em>. Pas de titres H1/H2.n";
$prompt .= "5) Retournez STRICTEMENT un JSON valide avec les clés: long_html, short_html.nn";
$prompt .= "Données produit:n";
$prompt .= "- Titre: " . ($payload['title'] ?? '') . "n";
if (!empty($payload['sku'])) {
$prompt .= "- SKU: " . $payload['sku'] . "n";
}
if (!empty($payload['categories'])) {
$prompt .= "- Catégories: " . implode(', ', (array) $payload['categories']) . "n";
}
if (!empty($payload['tags'])) {
$prompt .= "- Tags: " . implode(', ', (array) $payload['tags']) . "n";
}
if (!empty($attrs_lines)) {
$prompt .= "- Attributs:n" . implode("n", $attrs_lines) . "n";
}
// Le prix est optionnel: utile si vous voulez positionnement "entrée de gamme/premium".
if (!empty($payload['price'])) {
$prompt .= "- Prix actuel (indicatif): " . $payload['price'] . "n";
}
if ($notes_clean !== '') {
$prompt .= "nNotes internes:n" . $notes_clean . "n";
}
// Si une description existe déjà, on peut demander une amélioration plutôt qu'une réécriture totale.
$existing = trim((string) ($payload['description_existing'] ?? ''));
if ($existing !== '' && mb_strlen($existing) > 80) {
$prompt .= "nTexte existant (à améliorer sans changer le sens):n" . $existing . "n";
}
$prompt .= "nFormat attendu (exemple):n";
$prompt .= "{"long_html":"<p>...</p>","short_html":"<p>...</p>"}n";
return $prompt;
}
5) เรียกใช้ AI API ผ่าน wp_remote_post()
ตัวอย่างเช่น การใช้ API “Responses” ของ OpenAI หากคุณใช้ผู้ให้บริการรายอื่น (Anthropic, Mistral, Google) โครงสร้างจะเปลี่ยนไป แต่หลักการยังคงเหมือนเดิม ได้แก่ การหมดเวลา การจัดการข้อผิดพลาด และการแยกวิเคราะห์อย่างเข้มงวด
ฉันบังคับให้ส่งข้อมูลในรูปแบบ JSON ในข้อความแจ้งเตือน จากนั้นจึงทำการวิเคราะห์ข้อมูลนั้นที่ฝั่งเซิร์ฟเวอร์ วิธีนี้ช่วยหลีกเลี่ยงการตอบสนองที่ "ละเอียดเกินไป" ถึง 80% ซึ่งเป็นสาเหตุที่ทำให้การแทรกข้อมูลล้มเหลว
function bpcab_call_openai_responses_api(string $prompt) {
$endpoint = 'https://api.openai.com/v1/responses';
$body = [
// Modèle: choisissez un modèle "mini" pour réduire les coûts si la qualité vous suffit.
// Adaptez selon votre compte et les modèles disponibles.
'model' => 'gpt-4.1-mini',
'input' => [
[
'role' => 'user',
'content' => [
[
'type' => 'input_text',
'text' => $prompt,
],
],
],
],
// Limite raisonnable: descriptions produit, pas un roman.
'max_output_tokens' => 700,
'temperature' => 0.6,
];
$args = [
'timeout' => 25, // Évitez 60s: en admin, ça se ressent vite.
'headers' => [
'Content-Type' => 'application/json',
'Authorization' => 'Bearer ' . BPCAB_OPENAI_API_KEY,
],
'body' => wp_json_encode($body),
];
$res = wp_remote_post($endpoint, $args);
if (is_wp_error($res)) {
return new WP_Error('http_error', 'Erreur HTTP vers l’API IA: ' . $res->get_error_message());
}
$code = (int) wp_remote_retrieve_response_code($res);
$raw = (string) wp_remote_retrieve_body($res);
if ($code < 200 || $code >= 300) {
// Log minimal (évitez de logger des données sensibles).
error_log('[BPCAB AI] API non-200: ' . $code . ' body=' . substr($raw, 0, 500));
return new WP_Error('api_non_200', 'Réponse IA invalide (HTTP ' . $code . '). Vérifiez votre clé/quota.');
}
$json = json_decode($raw, true);
if (!is_array($json)) {
return new WP_Error('json_decode', 'Réponse IA non JSON (json_decode a échoué).');
}
// Récupération du texte: selon l’API, la sortie peut être structurée.
// On essaie plusieurs chemins connus, puis on échoue proprement.
$text = '';
// Chemin courant: output_text agrégé
if (isset($json['output_text']) && is_string($json['output_text'])) {
$text = $json['output_text'];
}
// Fallback: certaines réponses contiennent output[] avec content[]
if ($text === '' && !empty($json['output']) && is_array($json['output'])) {
foreach ($json['output'] as $item) {
if (!is_array($item) || empty($item['content']) || !is_array($item['content'])) {
continue;
}
foreach ($item['content'] as $c) {
if (is_array($c) && ($c['type'] ?? '') === 'output_text' && isset($c['text'])) {
$text .= (string) $c['text'];
}
}
}
}
$text = trim($text);
if ($text === '') {
error_log('[BPCAB AI] Sortie vide. Raw=' . substr($raw, 0, 500));
return new WP_Error('empty_output', 'L’API IA a renvoyé une sortie vide.');
}
// On attend un JSON strict dans $text
$out = json_decode($text, true);
if (!is_array($out)) {
error_log('[BPCAB AI] JSON attendu mais non parsable. Text=' . substr($text, 0, 500));
return new WP_Error('bad_format', 'Format IA inattendu. Ajustez le prompt (JSON strict).');
}
$long = isset($out['long_html']) ? (string) $out['long_html'] : '';
$short = isset($out['short_html']) ? (string) $out['short_html'] : '';
return [
'long' => $long,
'short' => $short,
];
}
6) อัปเดตผลิตภัณฑ์ (เนื้อหา + ตัวอย่าง)
โพสต์ WordPress ที่เป็นต้นทางจะได้รับการอัปเดต จากนั้น WooCommerce จะอ่านฟิลด์เหล่านี้เพื่อแสดงคำอธิบาย ฉันกำลังใช้งาน wp_update_post() เพื่อให้เป็นไปตามขั้นตอนการทำงานมาตรฐานของ WordPress (เช่น hooks, การแก้ไขหากเปิดใช้งาน ฯลฯ)
function bpcab_update_product_descriptions(int $product_id, string $long_html, string $short_html) {
$update = [
'ID' => $product_id,
'post_content' => $long_html,
'post_excerpt' => $short_html,
];
$res = wp_update_post(wp_slash($update), true, false);
if (is_wp_error($res)) {
return new WP_Error('update_failed', 'Échec mise à jour produit: ' . $res->get_error_message());
}
// Optionnel: forcer une mise à jour du produit WooCommerce (index, lookup tables, etc.)
if (function_exists('wc_get_product')) {
$product = wc_get_product($product_id);
if ($product) {
$product->save();
}
}
return true;
}
รหัสที่ประกอบเสร็จสมบูรณ์
คัดลอกและวางไฟล์นี้ลงใน wp-content/mu-plugins/bpcab-ai-woo-descriptions.phpสร้างไฟล์ JS ด้วย bpcab-ai-woo-admin.js ถัดจากนั้น (ตามที่ระบุไว้ข้างต้น)
<?php
/**
* Plugin Name: BPCAB - IA descriptions produits WooCommerce
* Description: Génère des descriptions produits via IA depuis l'admin WooCommerce (WP 6.9.4+, PHP 8.1+).
* Version: 1.0.0
*/
if (!defined('ABSPATH')) {
exit;
}
/**
* Meta box sur l'écran produit.
*/
add_action('add_meta_boxes', function () {
add_meta_box(
'bpcab_ai_product_desc',
'Descriptions IA',
'bpcab_render_ai_metabox',
'product',
'side',
'high'
);
});
function bpcab_render_ai_metabox(WP_Post $post): void {
$product_id = (int) $post->ID;
if (!current_user_can('edit_product', $product_id)) {
echo '<p>Vous n’avez pas les droits pour modifier ce produit.</p>';
return;
}
wp_nonce_field('bpcab_ai_generate_desc', 'bpcab_ai_nonce');
echo '<p>
<label for="bpcab_ai_notes"><strong>Notes internes (optionnel)</strong></label>
<textarea id="bpcab_ai_notes" style="width:100%;min-height:70px;" placeholder="Ex: ton premium, mentionner la garantie 2 ans, éviter les superlatifs..."></textarea>
</p>';
echo '<p>
<button type="button" class="button button-primary" id="bpcab-ai-generate" data-product-id="' . esc_attr((string) $product_id) . '">
Générer avec IA
</button>
</p>';
echo '<div id="bpcab-ai-status" style="margin-top:8px;"></div>';
}
/**
* JS admin (uniquement sur l'écran produit).
*/
add_action('admin_enqueue_scripts', function (string $hook_suffix) {
if (!in_array($hook_suffix, ['post.php', 'post-new.php'], true)) {
return;
}
$screen = get_current_screen();
if (!$screen || $screen->post_type !== 'product') {
return;
}
wp_enqueue_script(
'bpcab-ai-woo-admin',
plugins_url('bpcab-ai-woo-admin.js', __FILE__),
['jquery'],
'1.0.0',
true
);
wp_localize_script('bpcab-ai-woo-admin', 'BPCAB_AI', [
'ajaxUrl' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('bpcab_ai_generate_desc'),
]);
});
/**
* Endpoint AJAX sécurisé.
*/
add_action('wp_ajax_bpcab_ai_generate_product_desc', function () {
$nonce = isset($_POST['nonce']) ? sanitize_text_field((string) $_POST['nonce']) : '';
if (!wp_verify_nonce($nonce, 'bpcab_ai_generate_desc')) {
wp_send_json_error(['message' => 'Nonce invalide. Rechargez la page produit.'], 403);
}
$product_id = isset($_POST['product_id']) ? (int) $_POST['product_id'] : 0;
if ($product_id <= 0) {
wp_send_json_error(['message' => 'ID produit invalide.'], 400);
}
if (!current_user_can('edit_product', $product_id)) {
wp_send_json_error(['message' => 'Droits insuffisants.'], 403);
}
if (!defined('BPCAB_OPENAI_API_KEY') || !BPCAB_OPENAI_API_KEY) {
wp_send_json_error(['message' => 'Clé API manquante. Définissez BPCAB_OPENAI_API_KEY dans wp-config.php.'], 500);
}
$notes = isset($_POST['notes']) ? wp_kses_post((string) $_POST['notes']) : '';
$result = bpcab_ai_generate_and_update_product($product_id, $notes);
if (is_wp_error($result)) {
wp_send_json_error([
'message' => $result->get_error_message(),
'code' => $result->get_error_code(),
], 500);
}
wp_send_json_success(['updated' => true]);
});
function bpcab_ai_generate_and_update_product(int $product_id, string $notes = '') {
if (!function_exists('wc_get_product')) {
return new WP_Error('woocommerce_missing', 'WooCommerce ne semble pas actif.');
}
$product = wc_get_product($product_id);
if (!$product) {
return new WP_Error('product_missing', 'Produit introuvable.');
}
$user_id = get_current_user_id();
$rl_key = 'bpcab_ai_rl_' . $user_id . '_' . $product_id;
if (get_transient($rl_key)) {
return new WP_Error('rate_limited', 'Vous générez trop vite. Attendez 30 secondes et réessayez.');
}
set_transient($rl_key, 1, 30);
$payload = bpcab_build_product_payload_for_prompt($product);
$fingerprint = hash('sha256', wp_json_encode([
'payload' => $payload,
'notes' => $notes,
'v' => '1.0.0',
]));
$cache_key = 'bpcab_ai_desc_' . $product_id . '_' . substr($fingerprint, 0, 12);
$cached = get_transient($cache_key);
if (is_array($cached) && isset($cached['long'], $cached['short'])) {
return bpcab_update_product_descriptions($product_id, $cached['long'], $cached['short']);
}
$prompt = bpcab_build_prompt($payload, $notes);
$ai = bpcab_call_openai_responses_api($prompt);
if (is_wp_error($ai)) {
return $ai;
}
$long = wp_kses_post($ai['long'] ?? '');
$short = wp_kses_post($ai['short'] ?? '');
if (mb_strlen(wp_strip_all_tags($long)) < 80) {
return new WP_Error('ai_empty', 'La réponse IA est trop courte ou vide. Vérifiez vos données produit et le prompt.');
}
if (mb_strlen(wp_strip_all_tags($short)) < 30) {
$short = wp_trim_words(wp_strip_all_tags($long), 35, '…');
}
set_transient($cache_key, ['long' => $long, 'short' => $short], 30 * DAY_IN_SECONDS);
return bpcab_update_product_descriptions($product_id, $long, $short);
}
function bpcab_build_product_payload_for_prompt(WC_Product $product): array {
$product_id = $product->get_id();
$cats = wp_get_post_terms($product_id, 'product_cat', ['fields' => 'names']);
$tags = wp_get_post_terms($product_id, 'product_tag', ['fields' => 'names']);
$attributes_out = [];
foreach ($product->get_attributes() as $attr) {
if ($attr->is_taxonomy()) {
$taxonomy = $attr->get_name();
$label = wc_attribute_label($taxonomy);
$terms = wp_get_post_terms($product_id, $taxonomy, ['fields' => 'names']);
$attributes_out[] = [
'label' => $label,
'values' => array_values(array_filter(array_map('sanitize_text_field', $terms))),
];
} else {
$attributes_out[] = [
'label' => sanitize_text_field($attr->get_name()),
'values' => array_values(array_filter(array_map('sanitize_text_field', $attr->get_options()))),
];
}
}
$sku = (string) $product->get_sku();
$price = $product->get_price();
$regular = $product->get_regular_price();
$sale = $product->get_sale_price();
return [
'title' => sanitize_text_field($product->get_name()),
'sku' => sanitize_text_field($sku),
'categories' => array_values(array_filter(array_map('sanitize_text_field', (array) $cats))),
'tags' => array_values(array_filter(array_map('sanitize_text_field', (array) $tags))),
'attributes' => $attributes_out,
'price' => $price !== '' ? (string) $price : '',
'regular_price' => $regular !== '' ? (string) $regular : '',
'sale_price' => $sale !== '' ? (string) $sale : '',
'short_description_existing' => wp_strip_all_tags((string) $product->get_short_description()),
'description_existing' => wp_strip_all_tags((string) $product->get_description()),
];
}
function bpcab_build_prompt(array $payload, string $notes = ''): string {
$attrs_lines = [];
foreach (($payload['attributes'] ?? []) as $attr) {
$label = $attr['label'] ?? '';
$values = $attr['values'] ?? [];
if (!$label || empty($values)) {
continue;
}
$attrs_lines[] = '- ' . $label . ' : ' . implode(', ', $values);
}
$notes_clean = trim(wp_strip_all_tags($notes));
$prompt = "Vous êtes un rédacteur e-commerce senior. Rédigez pour WooCommerce une description produit en FR.nn";
$prompt .= "Règles STRICTES:n";
$prompt .= "1) N'inventez aucune caractéristique non fournie.n";
$prompt .= "2) Pas de superlatifs gratuits ("le meilleur", "incroyable").n";
$prompt .= "3) Style clair, concret, orienté bénéfices et usages.n";
$prompt .= "4) HTML autorisé: <p>, <ul>, <li>, <strong>, <em>. Pas de titres H1/H2.n";
$prompt .= "5) Retournez STRICTEMENT un JSON valide avec les clés: long_html, short_html.nn";
$prompt .= "Données produit:n";
$prompt .= "- Titre: " . ($payload['title'] ?? '') . "n";
if (!empty($payload['sku'])) {
$prompt .= "- SKU: " . $payload['sku'] . "n";
}
if (!empty($payload['categories'])) {
$prompt .= "- Catégories: " . implode(', ', (array) $payload['categories']) . "n";
}
if (!empty($payload['tags'])) {
$prompt .= "- Tags: " . implode(', ', (array) $payload['tags']) . "n";
}
if (!empty($attrs_lines)) {
$prompt .= "- Attributs:n" . implode("n", $attrs_lines) . "n";
}
if (!empty($payload['price'])) {
$prompt .= "- Prix actuel (indicatif): " . $payload['price'] . "n";
}
if ($notes_clean !== '') {
$prompt .= "nNotes internes:n" . $notes_clean . "n";
}
$existing = trim((string) ($payload['description_existing'] ?? ''));
if ($existing !== '' && mb_strlen($existing) > 80) {
$prompt .= "nTexte existant (à améliorer sans changer le sens):n" . $existing . "n";
}
$prompt .= "nFormat attendu (exemple):n";
$prompt .= "{"long_html":"<p>...</p>","short_html":"<p>...</p>"}n";
return $prompt;
}
function bpcab_call_openai_responses_api(string $prompt) {
$endpoint = 'https://api.openai.com/v1/responses';
$body = [
'model' => 'gpt-4.1-mini',
'input' => [
[
'role' => 'user',
'content' => [
[
'type' => 'input_text',
'text' => $prompt,
],
],
],
],
'max_output_tokens' => 700,
'temperature' => 0.6,
];
$args = [
'timeout' => 25,
'headers' => [
'Content-Type' => 'application/json',
'Authorization' => 'Bearer ' . BPCAB_OPENAI_API_KEY,
],
'body' => wp_json_encode($body),
];
$res = wp_remote_post($endpoint, $args);
if (is_wp_error($res)) {
return new WP_Error('http_error', 'Erreur HTTP vers l’API IA: ' . $res->get_error_message());
}
$code = (int) wp_remote_retrieve_response_code($res);
$raw = (string) wp_remote_retrieve_body($res);
if ($code < 200 || $code >= 300) {
error_log('[BPCAB AI] API non-200: ' . $code . ' body=' . substr($raw, 0, 500));
return new WP_Error('api_non_200', 'Réponse IA invalide (HTTP ' . $code . '). Vérifiez votre clé/quota.');
}
$json = json_decode($raw, true);
if (!is_array($json)) {
return new WP_Error('json_decode', 'Réponse IA non JSON (json_decode a échoué).');
}
$text = '';
if (isset($json['output_text']) && is_string($json['output_text'])) {
$text = $json['output_text'];
}
if ($text === '' && !empty($json['output']) && is_array($json['output'])) {
foreach ($json['output'] as $item) {
if (!is_array($item) || empty($item['content']) || !is_array($item['content'])) {
continue;
}
foreach ($item['content'] as $c) {
if (is_array($c) && ($c['type'] ?? '') === 'output_text' && isset($c['text'])) {
$text .= (string) $c['text'];
}
}
}
}
$text = trim($text);
if ($text === '') {
error_log('[BPCAB AI] Sortie vide. Raw=' . substr($raw, 0, 500));
return new WP_Error('empty_output', 'L’API IA a renvoyé une sortie vide.');
}
$out = json_decode($text, true);
if (!is_array($out)) {
error_log('[BPCAB AI] JSON attendu mais non parsable. Text=' . substr($text, 0, 500));
return new WP_Error('bad_format', 'Format IA inattendu. Ajustez le prompt (JSON strict).');
}
return [
'long' => isset($out['long_html']) ? (string) $out['long_html'] : '',
'short' => isset($out['short_html']) ? (string) $out['short_html'] : '',
];
}
function bpcab_update_product_descriptions(int $product_id, string $long_html, string $short_html) {
$update = [
'ID' => $product_id,
'post_content' => $long_html,
'post_excerpt' => $short_html,
];
$res = wp_update_post(wp_slash($update), true, false);
if (is_wp_error($res)) {
return new WP_Error('update_failed', 'Échec mise à jour produit: ' . $res->get_error_message());
}
if (function_exists('wc_get_product')) {
$product = wc_get_product($product_id);
if ($product) {
$product->save();
}
}
return true;
}
คำอธิบายของโค้ด
ทำไมถึงใช้ปุ่ม (AJAX) แทนที่จะใช้ hook อัตโนมัติ?
ใน WooCommerce สินค้าสามารถบันทึกได้หลายครั้งโดยไม่ต้องคลิก "อัปเดต" เช่น การบันทึกอัตโนมัติ การแก้ไข การอัปเดตข้อมูลจากปลั๊กอินอื่น การซิงค์สินค้าคงคลัง ฯลฯ หากคุณเชื่อมต่อ AI เข้ากับระบบ save_post_product หากไม่มีมาตรการป้องกัน คุณอาจเรียกใช้ API โดยไม่ได้รับอนุญาต
ปุ่มนี้บังคับให้เกิดการกระทำโดยเจตนา และนั่นทำให้การแก้ไขข้อผิดพลาดง่ายขึ้น: คุณคลิก คุณเห็นสถานะ คุณแก้ไขมันได้
เหตุใดจึงใช้ข้อมูลชั่วคราวแบบแฮช?
แคชแบบง่ายๆ "ต่อผลิตภัณฑ์" (เช่น: bpcab_ai_desc_123สิ่งนี้อาจทำให้เข้าใจผิดได้ง่าย เพราะผลิตภัณฑ์มีการเปลี่ยนแปลง ค่าแฮช SHA-256 ของข้อมูลและหมายเหตุรับประกันว่า: ข้อมูลนำเข้าเหมือนกัน → ผลลัพธ์เหมือนกัน → ไม่ต้องชำระเงินคืน
กรณีพิเศษจริงๆ: หากคุณแก้ไขข้อความแจ้งเตือน (โครงสร้าง กฎ) คุณต้องการล้างแคช ดังนั้นจึงมีช่องเล็กๆ อยู่ v ในแฮช
ทำไมถึงใช้ wp_kses_post() แทนที่จะใช้ sanitize_text_field()?
sanitize_text_field() ทำลายโค้ด HTML อย่างไรก็ตาม คำอธิบายสินค้าใน WooCommerce จำเป็นต้องมีรายการ ข้อความตัวหนา และย่อหน้า ในทางปฏิบัติ wp_kses_post() เป็นทางออกที่เหมาะสม: อนุญาตให้ใช้ HTML สำหรับโพสต์เดียว และลบสคริปต์ออก
ฉันยังคงเห็นเว็บไซต์ที่นำเอาคำตอบจาก AI แบบ "ดิบๆ" มาใส่ไว้ post_contentหาก AI ตรวจพบลิงก์ที่น่าสงสัยหรือโค้ด HTML ที่ผิดปกติ นั่นหมายความว่าคุณได้เปิดประตูสู่ช่องโหว่ที่ไม่จำเป็นแล้ว นี่ไม่ใช่การโจมตี XSS แบบ "อัตโนมัติ" (WordPress มีระบบกรองอยู่แล้วในบางส่วน) แต่คุณกำลังทำให้เรื่องยุ่งยากขึ้นสำหรับตัวเอง
ทำไมต้องขอเวลานอกสั้นๆ?
ในส่วนผู้ดูแลระบบ การตั้งค่าหมดเวลา 60 วินาทีจะบล็อก UI และทำให้ WordPress ดูเหมือนค้าง เวลาที่เหมาะสมที่สุดคือ 20-30 วินาที หากคุณมีผลิตภัณฑ์ที่ซับซ้อนมาก ควรพิจารณาใช้การสร้างแบบอะซิงโครนัส (cron/queue) หรือสำรวจตัวเลือกขั้นสูงเพิ่มเติม
ต้นทุนและการเพิ่มประสิทธิภาพ API
ค่าใช้จ่ายขึ้นอยู่กับโมเดลและปริมาณโทเค็น โดยทั่วไปแล้ว หน้าผลิตภัณฑ์ (คำถาม + คำตอบ) อาจมีค่าใช้จ่ายประมาณ... 800 ถึง 2000 โทเค็น ขึ้นอยู่กับจำนวนคุณลักษณะและความยาวที่ต้องการ สำหรับโมเดล "ขนาดเล็ก" มักจะมีต้นทุนต่อรุ่นต่ำมาก แต่ในระดับใหญ่ ต้นทุนจะมีความสำคัญ
การประมาณค่าอย่างง่าย (ต้องปรับให้เข้ากับแบบจำลองของคุณ)
- สมมติว่ามีโทเค็น 1200 โทเค็นต่อผลิตภัณฑ์ (อินพุต + เอาต์พุต)
- 1000 ผลิตภัณฑ์/เดือน → 1,2 ล้านโทเค็น/เดือน
- สำหรับรุ่น "มินิ" ราคาโดยทั่วไปจะสมเหตุสมผล แต่... ถ้าคุณสร้างใหม่ (หากไม่ใช้แคช) คุณจะสามารถคูณด้วย 3 หรือ 10 ได้อย่างรวดเร็ว
การปรับปรุงประสิทธิภาพที่ได้ผลจริง
- แคชด้วยลายนิ้วมือ (มีอยู่แล้ว): ให้ผลตอบแทนการลงทุนที่ดีที่สุด
- จำกัดผลลัพธ์ กับ
max_output_tokens: หลีกเลี่ยงการตอบคำถามอย่างยืดยาว - รุ่นเล็กกว่า สำหรับการผลิตจำนวนมากนั้น รุ่นที่มีกำลังมากกว่าจะใช้เฉพาะกับผลิตภัณฑ์ระดับพรีเมียมเท่านั้น
- ชุด (เวอร์ชันขั้นสูง): ประมวลผล 50 ผลิตภัณฑ์ใน cron ช่วงกลางคืน โดยกำหนดงบประมาณรายวัน
- ลดข้อความแจ้งเตือน : ห้ามส่งค่าแอตริบิวต์ที่ว่างเปล่า หรือคำอธิบายที่มีอยู่หากว่างเปล่า
รูปแบบขั้นสูงและกรณีการใช้งาน
ตัวเลือกที่ 1: สร้างเฉพาะคำอธิบายสั้นๆ (ข้อความย่อ)
มีประโยชน์เมื่อคำอธิบายสินค้าของคุณเขียนเสร็จแล้ว (หรือได้รับจากผู้ผลิต) แต่คุณต้องการข้อความสรุปที่ดึงดูดใจและสอดคล้องกันสำหรับหน้าหมวดหมู่สินค้า
- แก้ไขข้อความแจ้งเตือนให้ถามเฉพาะข้อมูลต่อไปนี้เท่านั้น
short_html. - ใน
bpcab_update_product_descriptions()อัปเดตเท่านั้นpost_excerpt.
ตัวเลือกที่ 2: การสร้างแบบอะซิงโครนัส (หลีกเลี่ยงการหมดเวลา)
บนเซิร์ฟเวอร์โฮสติ้งที่ทำงานช้า การเรียกใช้งานจากภายนอกอาจใช้เวลานานกว่า 25 วินาที ในกรณีนี้ ให้เรียกใช้งานงานที่เลื่อนเวลาออกไป:
- AJAX: บันทึก "คำขอ" (ข้อมูลเมตาของโพสต์) และตอบกลับทันที
- งาน Cron (WP-Cron หรือเซิร์ฟเวอร์ Cron) จะประมวลผลคำขอในคิว โดยประมวลผลครั้งละ 5 คำขอต่อนาที
ฉันไม่ได้ใส่โค้ดทั้งหมดไว้ที่นี่เพื่อให้สามารถคัดลอกได้ง่าย แต่ประเด็นสำคัญคือ อย่าเรียกใช้ AI ในคำขอของผู้ดูแลระบบ หากโครงสร้างพื้นฐานของคุณไม่เสถียร
ตัวเลือกที่ 3: ความเข้ากันได้กับ Divi 5 / Elementor / Avada
กระบวนการสร้างลิงก์เกิดขึ้นในฝั่ง WooCommerce ดังนั้นจึงยังคงใช้งานร่วมกันได้ ส่วนที่น่าสนใจคือ การแสดง "ป้ายกำกับ" หรือ "บล็อกไฮไลท์" บนหน้าสินค้าผ่านเครื่องมือสร้างสินค้าของคุณ
- Divi 5 คุณสามารถสร้างโมดูลที่อ่านข้อมูลได้
post_excerptหรือฟิลด์เมตา "จุดแข็ง" ที่สร้างขึ้นโดย AI หากคุณยังคงใช้งานต่อไปpost_content/post_excerptดิวิไม่มีอะไรพิเศษให้ทำ - Elementor ใช้ช่อง "คำอธิบายสินค้าแบบย่อ" แล้วมันจะแสดงขึ้นมา อัตโนมัติ ข้อความที่ตัดตอนมาฉบับปรับปรุงแล้ว
- Avada : คอมโพเนนต์ WooCommerce “เนื้อหาผลิตภัณฑ์” / “คำอธิบายผลิตภัณฑ์” แสดงฟิลด์เหล่านี้โดยไม่ต้องปรับแต่งใดๆ
เคล็ดลับที่ผมใช้บ่อยคือ: ขอให้ AI สร้างรายการให้ <ul> ระบุข้อดีในคำอธิบายแบบยาว จากนั้นจัดรูปแบบรายการนี้โดยใช้ธีม/เครื่องมือสร้าง คุณจะได้รับความสอดคล้องทางด้านภาพโดยไม่ต้องเขียนโค้ดเพิ่มเติม
ความปลอดภัยและแนวทางปฏิบัติที่ดีที่สุด
ห้ามเปิดเผยคีย์ API ทางฝั่งไคลเอ็นต์เด็ดขาด
ผู้ดูแลระบบ JS กำลังโทรอยู่ admin-ajax.phpกุญแจยังคงอยู่ที่ wp-config.phpหากคุณใส่คีย์ไว้ในสคริปต์ แม้แต่ในแผงควบคุมผู้ดูแลระบบ คีย์นั้นก็จะถูกคัดลอกไปยังที่ใดที่หนึ่ง (แคช ส่วนขยายเบราว์เซอร์ พร็อกซี) ในที่สุด
ตรวจสอบและจำกัด
- ความสามารถในการ :
edit_productอย่างน้อยที่สุด อย่าปล่อยให้บทบาท "shop_manager" ที่ควบคุมไม่ได้ก่อให้เกิดการสร้างโมเดลถึง 10,000 รุ่น - nonce : มีการตั้งค่าไว้แล้วเพื่อป้องกันคำขอ CSRF
- อัตราจำกัด : จำกัดเวลาการใช้งานชั่วคราว 30 วินาทีต่อผู้ใช้และผลิตภัณฑ์ หากต้องการใช้งานเพิ่มเติม ให้เพิ่มโควต้าต่อวัน (ตัวนับการใช้งานชั่วคราว)
กรองการตอบสนองของ AI ให้บริสุทธิ์
wp_kses_post() เป็นค่าต่ำสุด หากคุณต้องการกำหนดเงื่อนไขที่เข้มงวดกว่านี้ คุณสามารถส่งรายการแท็กที่อนุญาตไปยังได้ wp_kses() และปฏิเสธลิงก์ภายนอกใดๆ
GDPR / ข้อมูลที่ส่ง
ห้ามส่งข้อมูลส่วนบุคคล (ชื่อลูกค้า ที่อยู่ ฯลฯ) ที่นี่เราส่งเฉพาะข้อมูลผลิตภัณฑ์เท่านั้น หากคุณวางแผนที่จะปรับแต่งคำอธิบายสำหรับผู้ใช้ คุณจะเข้าสู่บริบท GDPR ที่ละเอียดอ่อนยิ่งขึ้น (พื้นฐานทางกฎหมาย ผู้รับเหมาช่วง หน่วยงานคุ้มครองข้อมูลส่วนบุคคล ฯลฯ)
ข้อผิดพลาดที่ควรหลีกเลี่ยงอย่างสมจริง
- คัดลอกโค้ดไปวางผิดที่ : ข้อความที่คัดลอกมาวาง
functions.phpธีมหลักจะหายไปในการอัปเดตครั้งต่อไป - ลืมเครื่องหมายเซมิโคลอนไปได้เลย : ข้อผิดพลาด PHP เพียงครั้งเดียว → หน้าจอว่างเปล่าในหน้าผู้ดูแลระบบ ทดสอบบนระบบทดสอบ (staging)
- ตะขอที่ไม่เหมาะสม : ทริกเกอร์บน
initousave_postหากไม่มีมาตรการป้องกัน → การโทรจาก AI โดยไม่ตั้งใจ - ทดสอบในสภาพแวดล้อมการใช้งานจริงโดยไม่มีการสำรองข้อมูล คุณสามารถเขียนทับคำอธิบายที่มีอยู่แล้วได้ทีละหลายรายการ
- PHP เก่าเกินไปแล้ว : ไวยากรณ์/รูปแบบการพิมพ์บางส่วนข้างต้นนั้นใช้กับ PHP เวอร์ชัน 8.1 ขึ้นไป หากใช้กับเวอร์ชัน 7.4 จะเกิดข้อผิดพลาด
วิธีการทดสอบและแก้ไขข้อผิดพลาด
1) เปิดใช้งานการบันทึกข้อมูลอย่างถูกต้อง
ใน wp-config.php (ในขั้นตอนการเตรียมการ) ให้เปิดใช้งาน:
define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
define('WP_DEBUG_DISPLAY', false);
จากนั้นคุณจะได้อ่าน wp-content/debug.logเอกสารทางการ: แก้ไขข้อบกพร่องใน WordPress.
2) ทดสอบกับผลิตภัณฑ์ที่ "เรียบง่าย" ก่อน
- กรรมสิทธิ์ที่ชัดเจน
- กรอกข้อมูลคุณลักษณะ 2-3 รายการ
- หมวดหมู่
หากใช้งานได้ ให้เปลี่ยนไปใช้ผลิตภัณฑ์แบบแปรผันที่มีคุณลักษณะหลายอย่าง ข้อความแจ้งเตือนที่ยาวเกินไปจะเพิ่มความเสี่ยงต่อผลลัพธ์ที่ไม่เป็นไปตามข้อกำหนด (หรือถูกตัดทอน)
3) ตรวจสอบคำขอ AJAX
- เปิดเบราว์เซอร์ DevTools → เครือข่าย →
admin-ajax.php. - ดูรหัส HTTP (200/403/500) และข้อมูล JSON ที่ส่งกลับมา
4) ตรวจสอบการตอบสนองของ API
หากพบข้อผิดพลาดเกี่ยวกับรูปแบบ JSON ให้บันทึกเฉพาะส่วนย่อย (ซึ่งได้ดำเนินการไปแล้ว) substr()อย่าบันทึกข้อความแจ้งเตือนทั้งหมดหากคุณใส่ข้อมูลที่ละเอียดอ่อนลงไป
ถ้าวิธีนั้นไม่ได้ผล
นี่คือแผนภูมิการวินิจฉัยที่ผมใช้บ่อยมากในการแก้ไขปัญหาการเชื่อมต่อระบบประเภทนี้
| อาการ | สาเหตุที่เป็นไปได้ | การตรวจสอบ | Solution |
|---|---|---|---|
| ปุ่ม "สร้าง" ไม่มีการทำงานใดๆ | JavaScript ไม่โหลดในหน้าจอผลิตภัณฑ์ | DevTools Console/Network, การขาดหายไปของ bpcab-ai-woo-admin.js |
ตรวจสอบ admin_enqueue_scriptsเส้นทาง plugins_url()และไฟล์ JS นั้นมีอยู่จริง |
| ข้อผิดพลาด 403 “Nonce ไม่ถูกต้อง” | ไม่ได้รับแจ้งเตือน หรือหน้าเว็บเก่าเกินไป | เครือข่าย → เพย์โหลด POST ประกอบด้วย nonce ? |
รีเฟรชหน้าสินค้า ตรวจสอบดู wp_localize_script และการกระทำของทูตวาติกัน |
| ข้อผิดพลาด 500 “คีย์ API หายไป” | ขาดหายตลอดเวลา / ว่างเปล่า | ตรวจสอบ wp-config.php และสิ่งแวดล้อม |
กำหนด BPCAB_OPENAI_API_KEYล้างแคช opcache หากจำเป็น |
| ข้อผิดพลาด HTTP 401/403 บนฝั่ง AI API | คีย์ไม่ถูกต้อง โครงการไม่ได้รับอนุญาต | บันทึก: “API ไม่ใช่รหัส 200” + รหัส | สร้างคีย์ใหม่ ตรวจสอบสิทธิ์การเข้าถึงโปรเจ็กต์ทางฝั่งผู้ให้บริการ |
| HTTP 429 | โควต้าเกินกำหนด / อัตราค่าบริการของซัพพลายเออร์สูงสุด | บันทึกข้อมูล + แดชบอร์ดซัพพลายเออร์ | เพิ่มฟังก์ชันการหน่วงเวลา/ลองใหม่ ลดความเร็วสัญญาณนาฬิกา เปิดใช้งานการแคช และใช้โมเดลที่มีน้ำหนักเบากว่า |
| “รูปแบบ AI ที่ไม่คาดคิด” | AI ส่งคืนข้อความที่ไม่ใช่ JSON | บันทึกผลลัพธ์บางส่วน | ทำให้ข้อความแจ้งเตือนเข้มงวดขึ้นหรือต่ำลง temperatureลดความยาวที่ร้องขอลง |
| คำอธิบายถูกบดขยี้ "แบบสุ่ม" | ทดสอบบนระบบใช้งานจริง + การคลิกหลายครั้ง + การบันทึกอัตโนมัติ | ประวัติการแก้ไข / บันทึก | ดำเนินการจัดเตรียมอุปกรณ์ เพิ่มการล็อกที่ยาวขึ้น (ชั่วคราว) และขอการยืนยัน |
สองข้อผิดพลาดที่พบได้บ่อย
- โค้ดตัวอย่างเสียหายเนื่องจากปลั๊กอินโค้ดตัวอย่าง หากคุณใช้ปลั๊กอินประเภท "โค้ดตัวอย่าง" ข้อผิดพลาดในการวิเคราะห์อาจทำให้โค้ดตัวอย่างใช้งานไม่ได้ ส่งผลให้หน้าจอแสดงผลสำหรับผู้ดูแลระบบอยู่ในสถานะที่ไม่เสถียร ปลั๊กอิน mu-plugin มีความเสถียรมากกว่าสำหรับโค้ดประเภทนี้
- ความขัดแย้งที่ซ่อนเร้น บางเว็บไซต์มีการแคชวัตถุแบบถาวรที่ค่อนข้างเข้มงวด หากตั้งค่าไม่ถูกต้อง วัตถุชั่วคราวอาจถูกแชร์ระหว่างสภาพแวดล้อมต่างๆ ได้ หากคุณพบคำอธิบายที่ไม่ตรงกัน ให้เริ่มต้นด้วยการปิดใช้งานแคชวัตถุชั่วคราวในสภาพแวดล้อมทดสอบ
ทรัพยากร
- WordPress: wp_remote_post()
- WordPress: Transients API
- WordPress: wp_kses_post()
- WordPress: Nonces
- ซอร์สโค้ดของ WordPress (ลิงก์สำรองบน GitHub)
- WordPress Core Trac
- OpenAI: การตอบสนองของ API (เอกสารอ้างอิง)
- PHP: json_decode()
- WooCommerce บน WordPress.org
คำถามที่พบบ่อย
ใช้งานได้กับสินค้าที่มีตัวเลือกหลากหลาย (หลายแบบ) หรือไม่?
ใช่ แต่โค้ดด้านบนสร้างคำอธิบายของ ผลิตภัณฑ์หลักถ้าคุณต้องการข้อความสำหรับแต่ละเวอร์ชัน คุณต้องวนซ้ำไปตามเวอร์ชันต่างๆ และจัดเก็บไว้ในเมตาแท็กเฉพาะ (และปรับการแสดงผล) โดยส่วนตัวแล้วฉันไม่ค่อยทำแบบนี้ เพราะมันมีค่าใช้จ่ายสูงและมักไม่จำเป็นจากมุมมอง SEO
ฉันสามารถป้องกันไม่ให้ AI พูดถึงราคาได้หรือไม่?
ใช่: ลบช่องข้อมูลนั้นออก price ของข้อมูลที่ส่งและบรรทัดที่เกี่ยวข้องในข้อความแจ้งเตือน ฉันแนะนำว่าอย่าใส่ราคาหากคุณจัดโปรโมชั่นบ่อยๆ มิเช่นนั้นข้อความของคุณจะล้าสมัย
เหตุใดจึงขอผลลัพธ์ในรูปแบบ JSON แทนที่จะเป็น HTML ธรรมดา?
เนื่องจากคุณต้องการสองฟิลด์ (แบบยาว + แบบสั้น) และการแยกวิเคราะห์ที่มีประสิทธิภาพ JSON ช่วยลดกรณีที่ AI เพิ่มประโยคที่อยู่นอกรูปแบบ และเมื่อเกิดข้อผิดพลาด คุณจะเห็นได้ทันที (ข้อผิดพลาด "bad_format")
ฉันสามารถใช้ Anthropic, Mistral หรือ Google แทนได้ไหม?
ใช่ค่ะ คงโครงสร้างเดิมไว้ (AJAX admin → wp_remote_post() → วิเคราะห์ → wp_kses_post() → อัปเดต) เฉพาะปลายทางและรูปแบบ JSON เท่านั้นที่เปลี่ยนแปลง หากคุณแจ้งผู้ให้บริการที่แน่นอนมา ฉันสามารถจัดหาฟังก์ชันให้คุณได้ bpcab_call_* เทียบเท่า
การทำเช่นนี้มีความเสี่ยงที่จะทำให้เกิดเนื้อหาซ้ำซ้อนหรือไม่?
หากผลิตภัณฑ์ของคุณมีความคล้ายคลึงกันมาก (คุณสมบัติเหมือนกัน ชื่อสินค้าเกือบเหมือนกัน) AI อาจสร้างข้อความที่คล้ายกัน เพื่อลดปัญหานี้ ให้เพิ่มข้อจำกัด "แยกความแตกต่างตามการใช้งาน" ในข้อความแจ้งเตือน และใส่รายละเอียดเฉพาะที่ไม่ซ้ำกัน (แบรนด์ วัสดุ ประโยชน์หลัก) แต่สำหรับแคตตาล็อกที่มีสินค้าประเภทเดียวกัน ความคล้ายคลึงกันบ้างเป็นสิ่งที่หลีกเลี่ยงไม่ได้
เราจะป้องกันไม่ให้ AI สร้างฟีเจอร์ใหม่ๆ ได้อย่างไร?
คุณจะไม่สามารถหลีกเลี่ยงความเสี่ยงนี้ได้อย่างสมบูรณ์ แต่คุณสามารถลดความเสี่ยงลงได้อย่างมากโดย:
- ห้ามการประดิษฐ์ดังกล่าวโดยชัดแจ้ง (ได้ดำเนินการไปแล้ว)
- ลดระดับลง
temperature(-0.3 0.6) - ให้ข้อมูลที่มีโครงสร้าง (คุณลักษณะ) เท่านั้น และหลีกเลี่ยง "หมายเหตุ" ที่คลุมเครือ
ฉันได้รับข้อผิดพลาด "รูปแบบ AI ที่ไม่คาดคิด" ฉันควรทำอะไรก่อนดี?
ลดความซับซ้อน: ลดจำนวนคุณลักษณะลง max_output_tokens สูงขึ้นไปอีกระดับ (ถ้ามันถูกตัดทอน) และมีข้อความแจ้งเตือนที่เข้มงวดกว่าเดิม (“ส่งคืนเฉพาะ JSON เท่านั้น ห้ามมีข้อความก่อนหรือหลัง”) จากประสบการณ์ของผม 9 ใน 10 ครั้ง มักจะเป็นเอาต์พุตที่ไม่ใช่ JSON
ทำไมปุ่มถึงเขียนว่า “ตกลง” แต่ฉันมองไม่เห็นอะไรด้านหน้าเลย?
บ่อยครั้ง ปัญหาอาจเกิดจากแคชของหน้าเว็บ (หรือแคชของวัตถุ) ที่แสดงเวอร์ชันเก่า ให้ล้างแคชและตรวจสอบว่าธีมของคุณแสดงผลได้อย่างถูกต้องหรือไม่ the_content() และโค้ดตัวอย่างมาตรฐานของ WooCommerce สำหรับ Elementor/Avada/Divi โปรดตรวจสอบให้แน่ใจว่าคุณไม่ได้แสดงฟิลด์ที่กำหนดเองแทน
ฉันสามารถดูตัวอย่างคำอธิบายก่อนที่จะถูกเขียนทับได้หรือไม่?
ใช่: แทนที่จะโทร wp_update_post()ส่งคืน long_html et short_html ในข้อความตอบกลับ AJAX ให้แสดงผลในรูปแบบโมดอล จากนั้นเพิ่มปุ่ม "ใช้" อีกปุ่มหนึ่ง นี่คือเวอร์ชันที่ผมใช้ในร้านค้าออนไลน์ที่มีผู้ใช้งานหลายคนแก้ไขข้อมูล
การสร้างลิงก์จำนวนมากจะส่งผลเสียต่อ SEO ของฉันหรือไม่?
หากคุณเผยแพร่เอกสารข้อมูลผลิตภัณฑ์ 500 ฉบับโดยไม่ผ่านการตรวจสอบแก้ไข คุณกำลังเสี่ยงต่อคุณภาพ (และด้วยเหตุนี้จึงเสี่ยงต่อ SEO ของคุณ) ขั้นตอนการทำงานที่ดีคือ: การสร้างโดย AI → การตรวจสอบโดยมนุษย์ → การเผยแพร่ และสำหรับผลิตภัณฑ์เชิงกลยุทธ์ คุณควรเขียนใหม่ทั้งหมด