Agar siz biron marta JSON-LD Schema.org faylini maqolaga "qo'lda" joylashtirgan bo'lsangiz, haqiqiy muammoni ko'rgansiz: 30 ta nashrdan so'ng, u nomuvofiq, to'liqsiz bo'lib qoladi va hech kim uni saqlab qolishga jur'at eta olmaydi.

Ehtiyoj / Foydalanish holati

Strukturalangan ma'lumotlar (JSON-LD) Google va boshqa qidiruv tizimlariga kontentni aniq tushunishga yordam beradi: maqola turi, muallif, nashr etilgan sana, asosiy rasm, "haqida" obyekt, FAQ va boshqalar. WordPressSizda allaqachon juda ko'p ishonchli ma'lumotlar mavjud (sarlavha, parcha, tanlangan rasm). Bo'shliq "ma'no"da: sub'ektlar, mavjudotlar, niyatlar va ba'zan to'g'ri. shrift Schema.org (Article vs. TechArticle vs. NewsArticle va boshqalar).

Sun'iy intellekt bu yerda a ishlab chiqarish uchun foydalidir semantik qatlam mazmuniga asoslanib, Sans Har bir maqola uchun 10 daqiqa vaqt sarflab, kalit so'zlar, ob'ektlar yoki "haqida" bo'limlarini tanlashingizdan qat'i nazar. Mening tajribamda, bu ayniqsa quyidagilar uchun foydalidir:

  • Texnik bloglar (WordPress, dev, data): AI texnologiyalar, versiyalar va kontseptsiyalarni yaxshi ajratib oladi.
  • Tahririyat veb-saytlari ko'plab muharrirlar bilan: Schema.org saytida hammani o'qitishsiz belgilashni standartlashtirish.
  • Elektron tijorat saytlarining "kontent"i (qo'llanmalar, taqqoslashlar): mahsulot tavsiflarini o'zgartirmasdan maqolalarni boyitish.

Oxir-oqibat, siz qanday amalga oshirishni bilib olasiz ulash (WordPress 6.9.4 / PHP 8.1+ bilan mos keladi) qaysi:

  • AI API orqali har bir maqola uchun JSON-LD Schema.org faylini yaratadi (chaqirish) wp_remote_post())
  • javobni keshlaydi (Transients API)
  • U faqat kerak bo'lganda (nashr/yangilanish) qayta tiklanadi.
  • JSON-LD ni ga kiritadi <head> old tomon
  • Xatolarni (vaqtinchalik tugashlar, kvota, noto'g'ri JSON) toza zaxira nusxalari bilan ishlaydi

Tez xulosa

  • Biz yaratamiz JSON-LD AI orqali pochta orqali, keyin biz aksiya meta postida (va biz qo'yamiz o'tkinchi (takroriy qo'ng'iroqlardan qochish uchun qo'shimcha ravishda).
  • API kaliti ichkarida WP-config.php orqali define(), hech qachon doimiy shaklda emas.
  • Biz AI API ni chaqiramiz wp_remote_post() + vaqt tugadi + xatolarni boshqarish.
  • Biz sun'iy intellektni qaytarib yuborishga majbur qilamiz Qattiq JSON (va biz buni PHP tomonida tasdiqlaymiz).
  • Biz JSON-LD skriptini quyidagi orqali kiritamiz wp_head (old tomonda) va biz administratordan qochamiz.
  • Biz faqat administrator uchun mo'ljallangan REST tugash nuqtasini qo'shamiz qayta tug'ilmoq talab bo'yicha (sifatni ta'minlashda amaliy).

Buning uchun qachon AI dan foydalanish kerak

Agar sizda shunchaki "maqola" ni hamma joyga qo'yish uchun emas, balki semantik boyitishga chinakam ehtiyoj bo'lsa, sun'iy intellektdan foydalaning. Yaxshi foydalanish holatlari:

  • Uzoq kontent (1000+ so'z), bu yerda obyektlarni (brendlar, vositalar, kontseptsiyalar) ajratib olish aniqlik keltiradi.
  • Tugallanmagan taksonomiyalar (ishonchsiz kategoriyalar/teglar) va siz toza "haqida/zikr qilish" maydonlarini xohlaysiz.
  • Jamoa yozuvi heterojen uslublar bilan: AI normallashtiradi.
  • SEO migratsiyasi (yangi mavzu, yangi SEO plagini): siz postlarni qayta yozmasdan izchil sxema yaratishingiz mumkin.

WordPress parchasi bo'sh bo'lgan va mualliflar juda ko'p o'zgargan saytlarda men ko'pincha afzallikni ko'rganman: AI tasodifiy "parcha" dan qochadigan izchil tavsif yaratadi.

Qachon AI dan foydalanmaslik kerak

Agar sxemangiz faqat mexanik va allaqachon deterministik bo'lsa, AI dan qoching.

  • Veb-saytlarni namoyish eting 10 sahifa bilan: buni qo'lda yoki SEO plagini orqali bajaring.
  • Oddiy diagrammalar (Tashkilot, Veb-sayt, BreadcrumbList) allaqachon sizning SEO plaginingiz tomonidan boshqariladi.
  • Maxfiy kontent (sog'liqni saqlash, huquqiy) agar siz xususiyatlarni "ixtiro qilish" uchun sun'iy intellektga tayansangiz. Bu yerda sun'iy intellekt ijodiy emas, balki ekstraktiv bo'lib qolishi kerak.
  • qattiq byudjet va har kuni nashr etiladigan katta hajmdagi postlar: agar siz juda tez-tez yangilasangiz, API narxi oshishi mumkin.

Klassik anti-naqsh - bu har safar sahifa ko'rsatilganda sun'iy intellektni chaqirish. Bu vaqt tugashi, keraksiz to'lovlar va ba'zan kod yomon himoyalangan bo'lsa, bo'sh sahifalar bilan tugaydi.

qo'ymaydi

Maqsadli muhit: WordPress 6.9.4 (2026-yil aprel) va PHP 8.1+.

API kaliti va saqlash

Siz OpenAI, Anthropic, Mistral yoki Google'dan foydalanishingiz mumkin. Men OpenAI misolini (API javoblari) keltiraman, chunki u qat'iy JSON tomonida juda barqaror, ammo plaginning tuzilishi provayderni almashtirishni osonlashtiradi.

Kalitni saqlang wp-config.php (yoki undan ham yaxshiroq, hosting provayderingiz tomonidan kiritilgan muhit o'zgaruvchisi). Misol:

/**
 * Clé API IA (ne jamais commiter ce fichier).
 * Idéalement, utilisez une variable d'environnement et fallback sur define().
 */
define('BPCAB_AI_OPENAI_API_KEY', 'REMPPLACEZ-MOI');

PHP kengaytmalari

  • cURL (ko'pincha yoqilgan) yoki allow_url_fopen (WordPress so'rovlardan foydalanadi, agar mavjud bo'lsa, cURLga tayanadi).
  • JSON (standart).

Foydali rasmiy manbalar

Yechim arxitekturasi

Plagin tomonidan ishlatiladigan matn oqimi:

WordPress muharriri (save_post) → ma'lumotlarni tayyorlash (sarlavha, kontent, parcha, rasm, muallif) → wp_remote_post() AI API ga → JSON javobi → tasdiqlash/dezinfektsiya → post meta + vaqtinchalik saqlash → front end (wp_head) in'ektsiyalari …

Nima uchun bu ish jarayoni ishlab chiqarishda yaxshi ishlaydi

  • Saqlash vaqtidagi avlod (yoki talab bo'yicha), displeyda emas: agar AI API sust bo'lsa, siz front-end renderlashni bloklamaysiz.
  • qoplama : qisqa o'tish davri muharrir "Yangilash" tugmasini 5 marta bosganda regeneratsiyalarning aylanishini oldini oladi.
  • Post meta : doimiy, eksport qilinadigan va versiyalashtiriladigan (agar sizda bosqichma-bosqich tizim mavjud bo'lsa).
  • JSON tasdiqlash : agar AI buzilgan matn yoki JSONni qaytarsa, hech narsa kiritilmaydi (zaxira).

Muhim eslatma: SEO plaginlari va dublikatlari

Yoast, Rank Math, SEOPress va boshqalar allaqachon JSON-LDlarni kiritmoqdalar. Agar o'zingiznikini qo'shsangiz, quyidagi xavf tug'dirasiz:

  • dublikatlari (ikkita Article)
  • nomuvofiqliklar (ikki muallif, ikkita rasm)

Men tavsiya qiladigan strategiya: in'ektsiya qiling "Qo'shimcha" sxema (masalan, about, mentions, keywords, audience) bittada Article siz nazorat qiladigan yoki aks holda ishlab chiqaradigan @graph toza. Quyidagi kod hosil qiladi @graph minimal va Tashkilot/Veb-saytni "qayta ixtiro qilish"dan qochadi.

To'liq kod - bosqichma-bosqich

Sizga uni qo'yishingizni maslahat beraman mu-plagin Agar siz uning mavzu o'zgarishlari va "tasodifiy o'chirishlar"dan omon qolishini istasangiz. Aks holda, standart plagin.

1-qadam — Minimal plagin tuzilishi

Fayl yarating: wp-content/mu-plugins/bpcab-ai-schema.php (agar kerak bo'lsa, papka yarating).

<?php
/**
 * Plugin Name: BPCAB AI Schema (JSON-LD)
 * Description: Génère et injecte des données structurées Schema.org via IA par article.
 * Version: 1.0.0
 * Requires at least: 6.9
 * Requires PHP: 8.1
 *
 * Conseil : placez ce fichier en mu-plugin pour éviter la désactivation accidentelle.
 */

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

2-qadam — Konstantalar, variantlar va himoya choralari

Biz uni boshidanoq himoya qilamiz: agar kalit mavjud bo'lmasa, biz hech narsa qilishga urinmaymiz. Men saytlarning 401 xatolarini qayta-qayta qaytarganini ko'p ko'rganman, chunki kod kalit yo'qolganiga qaramay, urinishda davom etgan.

/**
 * Retourne la clé API OpenAI depuis wp-config.php.
 */
function bpcab_ai_schema_get_openai_key(): string {
	if (defined('BPCAB_AI_OPENAI_API_KEY') && is_string(BPCAB_AI_OPENAI_API_KEY) && BPCAB_AI_OPENAI_API_KEY !== '') {
		return BPCAB_AI_OPENAI_API_KEY;
	}
	return '';
}

/**
 * Petite liste de post types autorisés.
 * Ajustez selon votre site (ex: 'post', 'page', 'guide', etc.).
 */
function bpcab_ai_schema_allowed_post_types(): array {
	return array('post');
}

3-qadam — "Ishonchli" WordPress ma'lumotlarini ajratib olish

Sun'iy intellekt sanalar, mualliflar yoki URL manzillarni ixtiro qilmasligi kerak. Biz ularni WordPressdan olamiz, keyin faqat sun'iy intellektdan semantik boyitishni so'raymiz.

/**
 * Construit un paquet de données "source of truth" depuis WordPress.
 * On évite d'envoyer des données inutiles (coût + confidentialité).
 */
function bpcab_ai_schema_build_post_payload(int $post_id): array {
	$post = get_post($post_id);
	if (!$post) {
		return array();
	}

	$title   = get_the_title($post);
	$content = $post->post_content;

	// Option : limiter la taille envoyée à l'API (coût + latence).
	// Ici, on garde le contenu brut, mais vous pouvez préférer wp_strip_all_tags().
	$content_plain = wp_strip_all_tags($content);
	$content_plain = mb_substr($content_plain, 0, 12000); // garde-fou

	$excerpt = has_excerpt($post) ? $post->post_excerpt : wp_trim_words($content_plain, 55, '…');

	$author_id = (int) $post->post_author;
	$author_name = $author_id ? get_the_author_meta('display_name', $author_id) : '';

	$permalink = get_permalink($post);
	$published = get_the_date(DATE_W3C, $post);
	$modified  = get_the_modified_date(DATE_W3C, $post);

	$image_id = get_post_thumbnail_id($post);
	$image_url = '';
	if ($image_id) {
		$image = wp_get_attachment_image_src($image_id, 'full');
		if (is_array($image) && !empty($image[0])) {
			$image_url = $image[0];
		}
	}

	return array(
		'post_id'      => $post_id,
		'post_type'    => $post->post_type,
		'title'        => $title,
		'excerpt'      => $excerpt,
		'content'      => $content_plain,
		'permalink'    => $permalink,
		'datePublished'=> $published,
		'dateModified' => $modified,
		'authorName'   => $author_name,
		'image'        => $image_url,
		'language'     => get_bloginfo('language'),
	);
}

4-qadam — AI “strict JSON” buyrugʻi + wp_remote_post() orqali API chaqiruvi

Ko'pgina implementatsiyalarni buzadigan muammo: AI JSON atrofidagi matnni yoki mos kelmaydigan maydonlarni qaytaradi. Biz qat'iy formatni joriy qilamiz va keyin tasdiqlaymiz.

OpenAI (javob nuqtasi) bilan misol. Rasmiy API havolasi: OpenAI javoblari API'si.

/**
 * Appelle OpenAI pour générer un JSON Schema.org (ou un fragment) basé sur le contenu.
 * Retourne un tableau PHP (décodé) ou WP_Error.
 */
function bpcab_ai_schema_call_openai(array $payload) {
	$api_key = bpcab_ai_schema_get_openai_key();
	if ($api_key === '') {
		return new WP_Error('bpcab_no_api_key', 'Clé API OpenAI manquante (BPCAB_AI_OPENAI_API_KEY).');
	}

	// Prompt : on demande un JSON STRICT, sans texte.
	$system = "Vous êtes un assistant spécialisé en SEO technique. Vous produisez uniquement du JSON strict, sans commentaire ni markdown.";
	$user = array(
		"Objectif: Générer un JSON-LD Schema.org pour un article WordPress.n"
		. "Contraintes:n"
		. "- Répondre uniquement avec un objet JSON valide.n"
		. "- Ne pas inventer d'URL, de dates, d'auteur.n"
		. "- Utiliser EXACTEMENT les valeurs fournies pour headline, url, datePublished, dateModified, author.name, image.n"
		. "- Ajouter des champs sémantiques utiles: keywords (array), about (array of Thing), mentions (array of Thing), articleSection (string), inLanguage.n"
		. "- Type recommandé: Article (ou TechArticle si le texte est technique).n"
		. "- Produire un JSON-LD avec @context et @graph.n"
		. "- Limiter keywords à 12 max. about/mentions: 8 max chacun.n"
		. "- Ne pas inclure Organization/WebSite si vous n'avez pas les données.nn"
		. "Données fiables (à utiliser telles quelles):n"
		. wp_json_encode(array(
			"headline" => $payload['title'] ?? '',
			"description" => $payload['excerpt'] ?? '',
			"url" => $payload['permalink'] ?? '',
			"datePublished" => $payload['datePublished'] ?? '',
			"dateModified" => $payload['dateModified'] ?? '',
			"authorName" => $payload['authorName'] ?? '',
			"image" => $payload['image'] ?? '',
			"inLanguage" => $payload['language'] ?? 'fr-FR',
		)) . "nn"
		. "Contenu (extrait):n"
		. ($payload['content'] ?? '')
	);

	$body = array(
		'model' => 'gpt-4.1-mini',
		'input' => array(
			array('role' => 'system', 'content' => $system),
			array('role' => 'user', 'content' => $user),
		),
		// Paramètres prudents : on veut du factuel, pas de créativité.
		'temperature' => 0.2,
		'max_output_tokens' => 900,
		// Demande explicite de sortie JSON. Selon l'API, ce champ peut évoluer.
		// Si OpenAI change, gardez la validation JSON côté PHP comme filet de sécurité.
		'text' => array('format' => array('type' => 'json_object')),
	);

	$args = array(
		'headers' => array(
			'Authorization' => 'Bearer ' . $api_key,
			'Content-Type'  => 'application/json',
		),
		'body' => wp_json_encode($body),
		'timeout' => 20, // évitez 60s : en front, c'est mort. Ici on est en save_post, mais restons raisonnables.
	);

	$response = wp_remote_post('https://api.openai.com/v1/responses', $args);

	if (is_wp_error($response)) {
		return $response;
	}

	$code = (int) wp_remote_retrieve_response_code($response);
	$raw  = wp_remote_retrieve_body($response);

	if ($code < 200 || $code >= 300) {
		return new WP_Error('bpcab_openai_http_error', 'Erreur HTTP OpenAI: ' . $code, array('body' => $raw));
	}

	$data = json_decode($raw, true);
	if (!is_array($data)) {
		return new WP_Error('bpcab_openai_bad_json', 'Réponse OpenAI non JSON (impossible à décoder).', array('body' => $raw));
	}

	// Selon le format de Responses API, le texte peut être dans output[...].
	// On essaie d'extraire un bloc texte puis de décoder ce JSON.
	$json_text = '';

	// Extraction robuste (évite de dépendre d'un seul chemin).
	if (!empty($data['output']) && is_array($data['output'])) {
		foreach ($data['output'] as $item) {
			if (!is_array($item) || empty($item['content']) || !is_array($item['content'])) {
				continue;
			}
			foreach ($item['content'] as $content_item) {
				if (is_array($content_item) && ($content_item['type'] ?? '') === 'output_text' && isset($content_item['text'])) {
					$json_text .= $content_item['text'];
				}
			}
		}
	}

	$json_text = trim($json_text);
	if ($json_text === '') {
		// Fallback : parfois l'API peut renvoyer directement un champ text.
		if (isset($data['text']) && is_string($data['text'])) {
			$json_text = trim($data['text']);
		}
	}

	if ($json_text === '') {
		return new WP_Error('bpcab_openai_empty_output', 'Sortie OpenAI vide ou non trouvée.', array('body' => $raw));
	}

	$schema = json_decode($json_text, true);
	if (!is_array($schema)) {
		return new WP_Error('bpcab_schema_not_json', 'Le contenu généré n’est pas un JSON valide.', array('generated' => $json_text));
	}

	return $schema;
}

5-qadam — JSON-LD tekshiruvi va sanitariya

Siz JSONni HTML kabi "dezinfektsiya qilmaysiz". To'g'ri yondashuv minimal tuzilmani tasdiqlash, xavfli narsalarni (skriptlarni) olib tashlash va namoyish vaqtida to'g'ri kodlashdir.

Umumiy xato: foydalanish wp_kses_post() JSON faylida. Bu qo'shtirnoq belgilarini buzadi va JSONni yaroqsiz qiladi. Bu yerda biz uni massiv sifatida tekshiramiz, keyin esa wp_json_encode().

/**
 * Validation minimale du schéma.
 * On vérifie @context et @graph. On peut être plus strict selon vos besoins.
 */
function bpcab_ai_schema_validate(array $schema) {
	if (!isset($schema['@context']) || !is_string($schema['@context'])) {
		return new WP_Error('bpcab_schema_missing_context', 'Schema invalide: @context manquant.');
	}
	if (!isset($schema['@graph']) || !is_array($schema['@graph'])) {
		return new WP_Error('bpcab_schema_missing_graph', 'Schema invalide: @graph manquant.');
	}

	// Protection basique : on refuse toute tentative d'injection de balises.
	$encoded = wp_json_encode($schema);
	if ($encoded === false) {
		return new WP_Error('bpcab_schema_encode_failed', 'Impossible d’encoder le schéma en JSON.');
	}
	if (stripos($encoded, '<script') !== false || stripos($encoded, '</script') !== false) {
		return new WP_Error('bpcab_schema_script_detected', 'Contenu suspect détecté dans le schéma.');
	}

	return true;
}

/**
 * Nettoyage "pragmatique" : on limite certaines longueurs et on force des types.
 */
function bpcab_ai_schema_normalize(array $schema): array {
	// Limite de taille pour éviter un JSON-LD énorme (performance + crawl).
	$max_graph_items = 12;
	if (isset($schema['@graph']) && is_array($schema['@graph']) && count($schema['@graph']) > $max_graph_items) {
		$schema['@graph'] = array_slice($schema['@graph'], 0, $max_graph_items);
	}

	return $schema;
}

6-qadam — vaqtinchalik kesh + meta-dan keyingi saqlash

Biz ikkita darajani birlashtiramiz:

  • post meta (doimiy) oldingi displey uchun
  • o'tkinchi (qisqa) juda tez tiklanishdan saqlanish uchun
/**
 * Clés de stockage.
 */
function bpcab_ai_schema_meta_key(): string {
	return '_bpcab_ai_schema_jsonld';
}
function bpcab_ai_schema_transient_key(int $post_id): string {
	return 'bpcab_ai_schema_lock_' . $post_id;
}

/**
 * Génère et stocke le schéma pour un post.
 */
function bpcab_ai_schema_generate_for_post(int $post_id) {
	$payload = bpcab_ai_schema_build_post_payload($post_id);
	if (empty($payload)) {
		return new WP_Error('bpcab_no_payload', 'Payload vide, post introuvable ?');
	}

	// Lock anti-boucle (ex: autosave + update en rafale).
	if (get_transient(bpcab_ai_schema_transient_key($post_id))) {
		return new WP_Error('bpcab_locked', 'Génération déjà en cours ou trop récente (lock transient).');
	}
	set_transient(bpcab_ai_schema_transient_key($post_id), 1, 2 * MINUTE_IN_SECONDS);

	$schema = bpcab_ai_schema_call_openai($payload);
	if (is_wp_error($schema)) {
		return $schema;
	}

	$valid = bpcab_ai_schema_validate($schema);
	if (is_wp_error($valid)) {
		return $valid;
	}

	$schema = bpcab_ai_schema_normalize($schema);

	// Stockage en post meta (tableau encodé JSON).
	$json = wp_json_encode($schema, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
	if ($json === false) {
		return new WP_Error('bpcab_encode_failed', 'Encodage JSON final impossible.');
	}

	update_post_meta($post_id, bpcab_ai_schema_meta_key(), $json);

	// On relâche le lock un peu plus tôt si tout s'est bien passé.
	delete_transient(bpcab_ai_schema_transient_key($post_id));

	return true;
}

7-qadam — save_post kancasi (muharrirni buzmasdan)

Noto'g'ri kanca yoki noto'g'ri shart, va siz avtomatik saqlash, tuzatishlar yoki Elementor oldindan ko'rishlarida AI ni chaqiryapsiz. Men buni doim ko'raman.

/**
 * Déclenchement à la sauvegarde.
 */
function bpcab_ai_schema_on_save_post(int $post_id, WP_Post $post, bool $update): void {
	// Éviter autosave, révisions, et contexte non pertinent.
	if (wp_is_post_autosave($post_id) || wp_is_post_revision($post_id)) {
		return;
	}

	// Éviter l'exécution sur les types non autorisés.
	if (!in_array($post->post_type, bpcab_ai_schema_allowed_post_types(), true)) {
		return;
	}

	// Éviter les brouillons: souvent le contenu est incomplet.
	// Ajustez selon votre workflow.
	if ($post->post_status !== 'publish') {
		return;
	}

	// Option : ne régénérer que si le contenu/titre a changé.
	// Ici, on régénère à chaque update publié (simple et fiable).
	$result = bpcab_ai_schema_generate_for_post($post_id);

	// On log en debug uniquement.
	if (is_wp_error($result) && defined('WP_DEBUG') && WP_DEBUG) {
		error_log('[BPCAB AI Schema] save_post error: ' . $result->get_error_code() . ' - ' . $result->get_error_message());
	}
}
add_action('save_post', 'bpcab_ai_schema_on_save_post', 20, 3);

8-qadam — JSON-LD ni wp_head ga kiritish

Biz faqat oldingi qismga, bitta tugunlarga va faqat meta tugun mavjud bo'lgandagina in'ektsiya qilamiz. Bu yerda sun'iy intellekt chaqiruvlari yo'q.

/**
 * Injecte le JSON-LD dans le head.
 */
function bpcab_ai_schema_print_jsonld(): void {
	if (is_admin()) {
		return;
	}
	if (!is_singular(bpcab_ai_schema_allowed_post_types())) {
		return;
	}

	$post_id = get_queried_object_id();
	if (!$post_id) {
		return;
	}

	$json = get_post_meta($post_id, bpcab_ai_schema_meta_key(), true);
	if (!is_string($json) || $json === '') {
		return;
	}

	// Vérification finale : JSON valide.
	$decoded = json_decode($json, true);
	if (!is_array($decoded)) {
		return;
	}

	// Encodage propre pour éviter les surprises.
	$out = wp_json_encode($decoded, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
	if ($out === false) {
		return;
	}

	echo "<script type="application/ld+json">n";
	echo $out;
	echo "n</script>n";
}
add_action('wp_head', 'bpcab_ai_schema_print_jsonld', 99);

9-qadam — Talab bo'yicha regeneratsiya uchun REST so'nggi nuqtasi (faqat administrator uchun)

Muharrir "sxema ko'rinmayapti" deb aytganda va siz postni qayta saqlamasdan (va kodga kirish huquqini bermasdan) qayta yaratmoqchi bo'lganingizda juda foydali. Biz uni imkoniyatlar + nonce bilan himoya qilamiz.

/**
 * Enregistre une route REST pour régénérer le schéma.
 */
function bpcab_ai_schema_register_rest_route(): void {
	register_rest_route('bpcab/v1', '/schema/regenerate/(?P<id>d+)', array(
		'methods' => 'POST',
		'permission_callback' => function (WP_REST_Request $request) {
			// Nonce REST standard: X-WP-Nonce (wp_create_nonce('wp_rest')).
			if (!is_user_logged_in()) {
				return false;
			}
			return current_user_can('edit_posts');
		},
		'callback' => function (WP_REST_Request $request) {
			$post_id = (int) $request['id'];
			if ($post_id <= 0) {
				return new WP_REST_Response(array('ok' => false, 'error' => 'ID invalide'), 400);
			}

			$post = get_post($post_id);
			if (!$post) {
				return new WP_REST_Response(array('ok' => false, 'error' => 'Post introuvable'), 404);
			}

			if (!current_user_can('edit_post', $post_id)) {
				return new WP_REST_Response(array('ok' => false, 'error' => 'Accès refusé'), 403);
			}

			$result = bpcab_ai_schema_generate_for_post($post_id);
			if (is_wp_error($result)) {
				return new WP_REST_Response(array(
					'ok' => false,
					'error' => $result->get_error_message(),
					'code' => $result->get_error_code(),
					'data' => $result->get_error_data(),
				), 500);
			}

			return new WP_REST_Response(array('ok' => true), 200);
		},
	));
}
add_action('rest_api_init', 'bpcab_ai_schema_register_rest_route');

To'liq yig'ilgan kod

Ushbu faylni nusxalash va joylashtirish wp-content/mu-plugins/bpcab-ai-schema.phpKeyin doimiyni qo'shing wp-config.phpBuni avval zaxira nusxasisiz ishlab chiqarishda sinab ko'rmang: bitta qavsni unutib qo'ysangiz va sayt ishlamay qoladi. oq ekran.

<?php
/**
 * Plugin Name: BPCAB AI Schema (JSON-LD)
 * Description: Génère et injecte des données structurées Schema.org via IA par article.
 * Version: 1.0.0
 * Requires at least: 6.9
 * Requires PHP: 8.1
 */

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

function bpcab_ai_schema_get_openai_key(): string {
	if (defined('BPCAB_AI_OPENAI_API_KEY') && is_string(BPCAB_AI_OPENAI_API_KEY) && BPCAB_AI_OPENAI_API_KEY !== '') {
		return BPCAB_AI_OPENAI_API_KEY;
	}
	return '';
}

function bpcab_ai_schema_allowed_post_types(): array {
	return array('post');
}

function bpcab_ai_schema_meta_key(): string {
	return '_bpcab_ai_schema_jsonld';
}

function bpcab_ai_schema_transient_key(int $post_id): string {
	return 'bpcab_ai_schema_lock_' . $post_id;
}

function bpcab_ai_schema_build_post_payload(int $post_id): array {
	$post = get_post($post_id);
	if (!$post) {
		return array();
	}

	$title   = get_the_title($post);
	$content = $post->post_content;

	$content_plain = wp_strip_all_tags($content);
	$content_plain = mb_substr($content_plain, 0, 12000);

	$excerpt = has_excerpt($post) ? $post->post_excerpt : wp_trim_words($content_plain, 55, '…');

	$author_id = (int) $post->post_author;
	$author_name = $author_id ? get_the_author_meta('display_name', $author_id) : '';

	$permalink = get_permalink($post);
	$published = get_the_date(DATE_W3C, $post);
	$modified  = get_the_modified_date(DATE_W3C, $post);

	$image_id = get_post_thumbnail_id($post);
	$image_url = '';
	if ($image_id) {
		$image = wp_get_attachment_image_src($image_id, 'full');
		if (is_array($image) && !empty($image[0])) {
			$image_url = $image[0];
		}
	}

	return array(
		'post_id'       => $post_id,
		'post_type'     => $post->post_type,
		'title'         => $title,
		'excerpt'       => $excerpt,
		'content'       => $content_plain,
		'permalink'     => $permalink,
		'datePublished' => $published,
		'dateModified'  => $modified,
		'authorName'    => $author_name,
		'image'         => $image_url,
		'language'      => get_bloginfo('language'),
	);
}

function bpcab_ai_schema_call_openai(array $payload) {
	$api_key = bpcab_ai_schema_get_openai_key();
	if ($api_key === '') {
		return new WP_Error('bpcab_no_api_key', 'Clé API OpenAI manquante (BPCAB_AI_OPENAI_API_KEY).');
	}

	$system = "Vous êtes un assistant spécialisé en SEO technique. Vous produisez uniquement du JSON strict, sans commentaire ni markdown.";
	$user = array(
		"Objectif: Générer un JSON-LD Schema.org pour un article WordPress.n"
		. "Contraintes:n"
		. "- Répondre uniquement avec un objet JSON valide.n"
		. "- Ne pas inventer d'URL, de dates, d'auteur.n"
		. "- Utiliser EXACTEMENT les valeurs fournies pour headline, url, datePublished, dateModified, author.name, image.n"
		. "- Ajouter des champs sémantiques utiles: keywords (array), about (array of Thing), mentions (array of Thing), articleSection (string), inLanguage.n"
		. "- Type recommandé: Article (ou TechArticle si le texte est technique).n"
		. "- Produire un JSON-LD avec @context et @graph.n"
		. "- Limiter keywords à 12 max. about/mentions: 8 max chacun.n"
		. "- Ne pas inclure Organization/WebSite si vous n'avez pas les données.nn"
		. "Données fiables (à utiliser telles quelles):n"
		. wp_json_encode(array(
			"headline" => $payload['title'] ?? '',
			"description" => $payload['excerpt'] ?? '',
			"url" => $payload['permalink'] ?? '',
			"datePublished" => $payload['datePublished'] ?? '',
			"dateModified" => $payload['dateModified'] ?? '',
			"authorName" => $payload['authorName'] ?? '',
			"image" => $payload['image'] ?? '',
			"inLanguage" => $payload['language'] ?? 'fr-FR',
		)) . "nn"
		. "Contenu (extrait):n"
		. ($payload['content'] ?? '')
	);

	$body = array(
		'model' => 'gpt-4.1-mini',
		'input' => array(
			array('role' => 'system', 'content' => $system),
			array('role' => 'user', 'content' => $user),
		),
		'temperature' => 0.2,
		'max_output_tokens' => 900,
		'text' => array('format' => array('type' => 'json_object')),
	);

	$args = array(
		'headers' => array(
			'Authorization' => 'Bearer ' . $api_key,
			'Content-Type'  => 'application/json',
		),
		'body' => wp_json_encode($body),
		'timeout' => 20,
	);

	$response = wp_remote_post('https://api.openai.com/v1/responses', $args);
	if (is_wp_error($response)) {
		return $response;
	}

	$code = (int) wp_remote_retrieve_response_code($response);
	$raw  = wp_remote_retrieve_body($response);

	if ($code < 200 || $code >= 300) {
		return new WP_Error('bpcab_openai_http_error', 'Erreur HTTP OpenAI: ' . $code, array('body' => $raw));
	}

	$data = json_decode($raw, true);
	if (!is_array($data)) {
		return new WP_Error('bpcab_openai_bad_json', 'Réponse OpenAI non JSON (impossible à décoder).', array('body' => $raw));
	}

	$json_text = '';
	if (!empty($data['output']) && is_array($data['output'])) {
		foreach ($data['output'] as $item) {
			if (!is_array($item) || empty($item['content']) || !is_array($item['content'])) {
				continue;
			}
			foreach ($item['content'] as $content_item) {
				if (is_array($content_item) && ($content_item['type'] ?? '') === 'output_text' && isset($content_item['text'])) {
					$json_text .= $content_item['text'];
				}
			}
		}
	}
	$json_text = trim($json_text);
	if ($json_text === '' && isset($data['text']) && is_string($data['text'])) {
		$json_text = trim($data['text']);
	}

	if ($json_text === '') {
		return new WP_Error('bpcab_openai_empty_output', 'Sortie OpenAI vide ou non trouvée.', array('body' => $raw));
	}

	$schema = json_decode($json_text, true);
	if (!is_array($schema)) {
		return new WP_Error('bpcab_schema_not_json', 'Le contenu généré n’est pas un JSON valide.', array('generated' => $json_text));
	}

	return $schema;
}

function bpcab_ai_schema_validate(array $schema) {
	if (!isset($schema['@context']) || !is_string($schema['@context'])) {
		return new WP_Error('bpcab_schema_missing_context', 'Schema invalide: @context manquant.');
	}
	if (!isset($schema['@graph']) || !is_array($schema['@graph'])) {
		return new WP_Error('bpcab_schema_missing_graph', 'Schema invalide: @graph manquant.');
	}

	$encoded = wp_json_encode($schema);
	if ($encoded === false) {
		return new WP_Error('bpcab_schema_encode_failed', 'Impossible d’encoder le schéma en JSON.');
	}
	if (stripos($encoded, '<script') !== false || stripos($encoded, '</script') !== false) {
		return new WP_Error('bpcab_schema_script_detected', 'Contenu suspect détecté dans le schéma.');
	}

	return true;
}

function bpcab_ai_schema_normalize(array $schema): array {
	$max_graph_items = 12;
	if (isset($schema['@graph']) && is_array($schema['@graph']) && count($schema['@graph']) > $max_graph_items) {
		$schema['@graph'] = array_slice($schema['@graph'], 0, $max_graph_items);
	}
	return $schema;
}

function bpcab_ai_schema_generate_for_post(int $post_id) {
	$payload = bpcab_ai_schema_build_post_payload($post_id);
	if (empty($payload)) {
		return new WP_Error('bpcab_no_payload', 'Payload vide, post introuvable ?');
	}

	if (get_transient(bpcab_ai_schema_transient_key($post_id))) {
		return new WP_Error('bpcab_locked', 'Génération déjà en cours ou trop récente (lock transient).');
	}
	set_transient(bpcab_ai_schema_transient_key($post_id), 1, 2 * MINUTE_IN_SECONDS);

	$schema = bpcab_ai_schema_call_openai($payload);
	if (is_wp_error($schema)) {
		return $schema;
	}

	$valid = bpcab_ai_schema_validate($schema);
	if (is_wp_error($valid)) {
		return $valid;
	}

	$schema = bpcab_ai_schema_normalize($schema);

	$json = wp_json_encode($schema, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
	if ($json === false) {
		return new WP_Error('bpcab_encode_failed', 'Encodage JSON final impossible.');
	}

	update_post_meta($post_id, bpcab_ai_schema_meta_key(), $json);
	delete_transient(bpcab_ai_schema_transient_key($post_id));

	return true;
}

function bpcab_ai_schema_on_save_post(int $post_id, WP_Post $post, bool $update): void {
	if (wp_is_post_autosave($post_id) || wp_is_post_revision($post_id)) {
		return;
	}
	if (!in_array($post->post_type, bpcab_ai_schema_allowed_post_types(), true)) {
		return;
	}
	if ($post->post_status !== 'publish') {
		return;
	}

	$result = bpcab_ai_schema_generate_for_post($post_id);
	if (is_wp_error($result) && defined('WP_DEBUG') && WP_DEBUG) {
		error_log('[BPCAB AI Schema] save_post error: ' . $result->get_error_code() . ' - ' . $result->get_error_message());
	}
}
add_action('save_post', 'bpcab_ai_schema_on_save_post', 20, 3);

function bpcab_ai_schema_print_jsonld(): void {
	if (is_admin()) {
		return;
	}
	if (!is_singular(bpcab_ai_schema_allowed_post_types())) {
		return;
	}

	$post_id = get_queried_object_id();
	if (!$post_id) {
		return;
	}

	$json = get_post_meta($post_id, bpcab_ai_schema_meta_key(), true);
	if (!is_string($json) || $json === '') {
		return;
	}

	$decoded = json_decode($json, true);
	if (!is_array($decoded)) {
		return;
	}

	$out = wp_json_encode($decoded, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
	if ($out === false) {
		return;
	}

	echo "<script type="application/ld+json">n";
	echo $out;
	echo "n</script>n";
}
add_action('wp_head', 'bpcab_ai_schema_print_jsonld', 99);

function bpcab_ai_schema_register_rest_route(): void {
	register_rest_route('bpcab/v1', '/schema/regenerate/(?P<id>d+)', array(
		'methods' => 'POST',
		'permission_callback' => function (WP_REST_Request $request) {
			if (!is_user_logged_in()) {
				return false;
			}
			return current_user_can('edit_posts');
		},
		'callback' => function (WP_REST_Request $request) {
			$post_id = (int) $request['id'];
			if ($post_id <= 0) {
				return new WP_REST_Response(array('ok' => false, 'error' => 'ID invalide'), 400);
			}

			$post = get_post($post_id);
			if (!$post) {
				return new WP_REST_Response(array('ok' => false, 'error' => 'Post introuvable'), 404);
			}

			if (!current_user_can('edit_post', $post_id)) {
				return new WP_REST_Response(array('ok' => false, 'error' => 'Accès refusé'), 403);
			}

			$result = bpcab_ai_schema_generate_for_post($post_id);
			if (is_wp_error($result)) {
				return new WP_REST_Response(array(
					'ok' => false,
					'error' => $result->get_error_message(),
					'code' => $result->get_error_code(),
					'data' => $result->get_error_data(),
				), 500);
			}

			return new WP_REST_Response(array('ok' => true), 200);
		},
	));
}
add_action('rest_api_init', 'bpcab_ai_schema_register_rest_route');

Kodning izohi

Nima uchun post metada saqlash kerak?

Post meta barqaror holatni ta'minlaydi. Agar AI API ishlamay qolsa, sizning JSON-LD faylingiz hali ham xizmat ko'rsatiladi. Va agar sizda sahifa keshi (Varnish, kesh plagini) bo'lsa, siz tebranishlardan qochasiz.

Nima uchun qo'shimcha vaqtinchalik "qulf" kerak?

Elementor yoki Divi dan foydalanadigan saytlarda "Yangilash" amali bir nechta saqlashlarni (avtomatik saqlash, tuzatish, yangilash) ishga tushirishi mumkin. Agar siz avtomatik saqlash/tuzatish uchun filtrlasangiz ham, men plaginlar orqali postni "qayta saqlash" uchun ikki marta qo'ng'iroqlarni ko'rdim. Vaqtinchalik funksiya ikki marta to'lovni oldini oladi.

Nima uchun tasdiqlash ataylab minimal?

Schema.org juda keng. Agar siz juda qat'iy tekshiruv o'tkazsangiz, foydali yaxshilanishlarni buzasiz (masalan, about en Thing vs DefinedTermBu yerda biz shunchaki invariantlarni tekshiramiz (@context, @graph) va biz shubhali kontentni rad etamiz.

Nima uchun biz JSONda wp_kses_post() dan foydalanmaymiz?

wp_kses_post() HTML filtridir. JSONga qo'llanilganda, u belgilarni buzadi va JSONni yaroqsiz holga keltiradi. Buning o'rniga, biz PHP massivini saqlaymiz, uning tuzilishini tekshiramiz va keyin kodlaymiz wp_json_encode().

Men tez-tez ko'radigan realistik xatolar

  • Kod functions.php fayliga joylashtirildi Ota-ona mavzusidan: mavzuni yangilash = yo'qolgan kod. Mu-plagindan foydalaning.
  • Nuqtali vergulni unutish yilda wp-config.php après define() → Darhol halokatli xato.
  • Noto'g'ri ilmoq (masalan: the_content) → Renderlash uchun sun'iy intellekt chaqiruvi → kechikish + xarajatlar.
  • Ishlab chiqarish sinovlari post turini cheklamasdan → siz saqlash tsikli orqali bir vaqtning o'zida 2000 ta postni qayta yaratasiz.

API xarajatlari va optimallashtirish

Narxi modelga va yuborilgan kontent hajmiga bog'liq. Matnning 12 000 belgidan iborat chegarasi bilan (bu ko'pincha HTMLsiz 2000–3000 so'zni anglatadi), siz o'rtacha so'rovni qabul qilasiz.

Realistik taxmin (kattalik tartibida)

  • 1 ta maqola = nashrga 1 ta sun'iy intellekt chaqiruvi + har bir muhim yangilanish uchun 1 ta chaqiruv.
  • Agar siz oyiga 30 ta maqola nashr qilsangiz va har birini o'rtacha 2 marta yangilasangiz: oyiga ~90 ta qo'ng'iroq.

Aniq narxlar uchun rasmiy sahifalarga qarang (u o'zgaradi). OpenAI: OpenAI narxlari.

Haqiqatan ham ishlaydigan optimallashtirishlar

  • Kirishni kamaytiring : butun kontent o'rniga (agar kontentingiz juda uzun bo'lsa) parchani + H2/H3 sarlavhalarini yuboring.
  • "Mini" model : kalit so'zlar/haqida/zikrlarni ajratib olish uchun yetarli miqdordan ko'proq.
  • Shartli regeneratsiya : kontentning xeshini (post meta) taqqoslang va faqat xesh o'zgarganda qayta yarating.
  • Oflayn rejimda to'plash (WP-CLI) ommaviy saqlash_post o'rniga migratsiyalar uchun.

Murakkab variantlar va foydalanish holatlari

1-variant — faqat tarkib o'zgargan bo'lsa qayta yaratiladi (xesh)

Kimdir sarlavhadagi vergulni tuzatganda pul to'lamaslik uchun xeshni saqlang.

function bpcab_ai_schema_hash_meta_key(): string {
	return '_bpcab_ai_schema_content_hash';
}

function bpcab_ai_schema_should_regenerate(int $post_id, array $payload): bool {
	$hash = hash('sha256', ($payload['title'] ?? '') . '|' . ($payload['excerpt'] ?? '') . '|' . ($payload['content'] ?? ''));
	$old  = get_post_meta($post_id, bpcab_ai_schema_hash_meta_key(), true);

	if (!is_string($old) || $old === '') {
		update_post_meta($post_id, bpcab_ai_schema_hash_meta_key(), $hash);
		return true;
	}

	if (!hash_equals($old, $hash)) {
		update_post_meta($post_id, bpcab_ai_schema_hash_meta_key(), $hash);
		return true;
	}

	return false;
}

Variant 2 — Divi 5 / Elementor / Avada mosligi

Ushbu quruvchilar ko'pincha tarkibni saqlaydilar post_content ichki qisqa kodlar/JSON bilan. Agar siz buni AIga yuborsangiz, u artefaktlarni ajratib olishi mumkin.

  • 5-bo'lim Ba'zan siz ichki tuzilmalarni ko'rasiz. wp_strip_all_tags() yordam, lekin har doim ham emas.
  • Elementor Kontentning bir qismi metama'lumotlarda (Elementor ma'lumotlari) joylashgan. Yakuniy renderlash xom versiyaga qaraganda aniqroq.
  • Avada Fusion Builder qisqa kodlari, xuddi shu muammo.

Ikki yondashuv:

  • "Xavfsiz" yondashuv (tavsiya etiladi): faqat ko'rinadigan matnni ajratib olish orqali the_content filtrlanadi, keyin teglar olib tashlanadi.
  • "Tezkor" yondashuv : saqlash post_content va shovqinni qabul qiling.

"Xavfsiz" versiya (buni ro'yxatlardagi siklda qilmaslikka ehtiyot bo'ling, uni save_post uchun saqlang):

function bpcab_ai_schema_get_rendered_text(WP_Post $post): string {
	// Applique les filtres (shortcodes, blocs, builders) pour obtenir un HTML proche du front.
	$html = apply_filters('the_content', $post->post_content);

	// Supprime scripts/styles éventuels.
	$html = preg_replace('#<scriptb[^>]*>.*?</script>#is', '', $html ?? '');
	$html = preg_replace('#<styleb[^>]*>.*?</style>#is', '', $html ?? '');

	$text = wp_strip_all_tags($html);
	return mb_substr($text, 0, 12000);
}

3-variant — agar maqolada FAQ bo'limi bo'lsa, FAQPage qo'shing

Agar maqolalaringiz tez-tez "FAQ" bilan tugasa, sun'iy intellekt savol-javob juftliklarini aniqlay oladi. Lekin qat'iy bo'ling: soxta FAQ SEO va tahririyat xavfini tug'diradi. Men faqat kontentda allaqachon aniq savollar mavjud bo'lgan taqdirdagina FAQ yaratishni tavsiya qilaman.

Siz so'rovga cheklov qo'shishingiz mumkin: "faqat allaqachon mavjud bo'lgan savollarni so'zma-so'z ajratib oling".

Xavfsizlik va eng yaxshi amaliyotlar

Mijoz tomonida kalitni hech qachon oshkor qilmang

Brauzerdan AI API ga JavaScript chaqiruvini amalga oshirishdan mutlaqo saqlaning. Kalit sizib chiqadi (DevTools, manba kodi, jurnallar). Bu yerda hamma narsa PHP orqali o'tadi wp_remote_post().

Tarifni cheklash

Vaqtinchalik "qulflash" - bu boshlanish. Agar sizda ko'p muallifli sayt bo'lsa, REST so'nggi nuqtasida har bir foydalanuvchi uchun tezlik chegarasini (masalan, har bir foydalanuvchi identifikatori uchun bitta vaqtinchalik) qo'shing.

Kirishni tasdiqlash

Foydalanuvchiga nazoratsiz REST parametri orqali AIga yuborilgan ixtiyoriy matnni kiritishga yo'l qo'ymang. Bu yerda oxirgi nuqta ... ni oladi. post_id va WordPress’dan foydali yuklamani qayta yaratdi.

GDPR / maxfiylik

  • Keraksiz shaxsiy ma'lumotlarni (elektron pochta, IP manzillar, maxfiy maydonlar) yubormang.
  • Aniq qonuniy asossiz izohlar yoki shakllarni yuborishdan saqlaning.
  • Agar kerak bo'lsa, subpudratchini (OpenAI/Anthropic/va boshqalar) reestringiz va maxfiylik siyosatingizda hujjatlashtiring.

Kesh mosligi

Agar siz agressiv sahifa keshidan foydalanayotgan bo'lsangiz, JSON-LD quyidagi orqali yuboriladi wp_head U hamma narsa kabi keshda saqlanadi. Maqsad shu. Xavf shundaki, metama'lumotlarni qayta yaratish va keshni (plagin keshi/CDN) tozalashni unutish kerak. Bunday holda, siz eski sxemani soatlab ko'rasiz.

Qanday qilib sinovdan o'tkazish va disk raskadrovka qilish kerak

1) Avval mahalliy sinov

Faollashtirish WP_DEBUG et WP_DEBUG_LOG yilda wp-config.phpMalumotnoma: WordPress-da disk raskadrovka.

define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);

2) JSON-LD to'g'ri chiqarilganligini tekshiring

  • Maqola sahifasini oching.
  • Manba kodini ko'ring.
  • Qidirmoq application/ld+json.

3) REST so'nggi nuqtasini (regeneratsiya) sinab ko'ring

Brauzeringizdan (administrator sifatida tizimga kirgan holda) konsolda fetch orqali yoki nonce yordamida curl orqali qo'ng'iroq qilishingiz mumkin. Misol curl (agar siz nonce ni administrator panelidan olsangiz):

curl -X POST "https://example.com/wp-json/bpcab/v1/schema/regenerate/123" 
  -H "X-WP-Nonce: VOTRE_NONCE" 
  -H "Content-Type: application/json"

4) JSON-LD ni tasdiqlang

Schema.org validatoridan yoki boy natijalarni sinash vositalaridan foydalaning. Men sizga "SEO blogi" havolasini emas, balki tuzilgan havolalarni beraman:

Agar bu ishlamasa

Buzilganda, deyarli har doim quyidagi holatlardan biri bo'ladi: kalit, kvota, noto'g'ri JSON yoki hook juda tez-tez ishga tushiriladi.

alomat Ehtimoliy sabab tekshiruv qaror
Manbada JSON-LD skripti yo'q Bo'sh metama'lumotlar (hech qachon yaratilmagan) yoki post_status ≠ nashr qilish Meta-ga qarang _bpcab_ai_schema_jsonld (nosozliklarni tuzatish plagini orqali) Maqolani nashr eting, keyin REST so'nggi nuqtasi orqali qayta yarating
Jurnallar: HTTP 401 / 403 API kaliti yo'q/noto'g'ri WP_DEBUG_LOG, xato kodi debug.log To'g'ri BPCAB_AI_OPENAI_API_KEY yilda wp-config.php
Jurnallar: vaqt tugashi Sekin API/Xosting provayderi chiquvchi so'rovlarni bloklaydi Sinov a wp_remote_get() ommaviy saytga Bir oz oshiring timeoutXavfsizlik devori sozlamalarini tekshiring va api.openai.com saytiga ruxsat bering.
Xato: “Yaratilgan kontent haqiqiy JSON emas” Sun'iy intellekt JSON atrofida matnni qaytardi Tekshirish generated xatolikda (disk raskadrovka) Buyruqni qat'iyroq qiling, saqlang text.formatharoratni pasaytirish
Ikkita diagramma. Sahifadagi maqola. SEO plagini allaqachon maqola kiritmoqda HTML manbasi: bir nechtasini qidirish "@type":"Article" Iloji bo'lsa, sxemangizni "fragment" ga o'zgartiring yoki SEO plaginining Article chiqishini o'chirib qo'ying

WordPressning o'ziga xos kamchiliklari

  • Parcha parcha plagini tomonidan buzilgan Ba'zi plaginlar yuklash tartibini o'zgartiradi. Mu-plaginlardan foydalanish orqali siz bu xavfni kamaytirasiz.
  • PHP versiyasi juda eski Agar sayt hali ham PHP 7.x da ishlayotgan bo'lsa, sizda xatoliklar bo'ladi. PHP 8.1+ ga e'tibor bering.
  • Ilgak ustuvorligi Agar boshqa plagin sizning save_postingizdan keyin kontentni o'zgartirsa, sxemangiz "kechikishda" bo'lishi mumkin. Ustuvorlikni sozlang (20 → 30) yoki oxirgi nuqta orqali qayta yarating.

resurslari

FAQ

Google sun'iy intellekt tomonidan yaratilgan tuzilgan ma'lumotlarni avtomatik ravishda "mukofotlaydimi"?

Yo'q. Belgilash talqin qilishga yordam beradi, lekin agar tarkib izchil bo'lmasa, sizga foyda bo'lmaydi. Haqiqiy foyda shundaki mustahkamlik et la aniqlik keng miqyosda.

Model tomonidan ishlab chiqarilgan JSON-LD ni kiritish xavflimi?

Ha, agar siz AI ixtiro qilishiga yo'l qo'ysangiz. Shuning uchun kod muhim maydonlar uchun WordPress qiymatlaridan foydalanishni majbur qiladi va in'ektsiyadan oldin tuzilmani tasdiqlaydi.

Buning o'rniga Anthropic yoki Mistral dan foydalanishim mumkinmi?

Ha. Xuddi shu arxitekturani saqlang: qat'iy JSON so'rovi, wp_remote_post()tasdiqlash json_decode()Faqat so'rov/javob formati o'zgaradi.

Nima uchun to'liq Tashkilot/Veb-sayt/BreadcrumbList sxemasini yaratmaslik kerak?

Bu elementlar ko'pincha allaqachon SEO plagini tomonidan boshqarilganligi va ular sayt bo'ylab (har bir maqola uchun emas) bo'lgani uchun, ikkita manbani aralashtirish nomuvofiqliklarni keltirib chiqaradi.

Yoast/Rank Math/SEOPress yordamida takrorlanishlardan qanday qochish mumkin?

Ikkita realistik variant:

  • Maqolani takrorlamaydigan sxema yaratish (masalan, a DefinedTermSet yoki Thing bog'liq)
  • SEO plaginining Schema chiqishini o'chirib qo'ying (agar bunday imkoniyat mavjud bo'lsa) va plaginingizga maqolani boshqarishga ruxsat bering.

Sahifalar uchun sxemani yarata olamanmi (post turi sahifasi)?

Ha, lekin "Maqola" ni majburlamang. Ba'zi sahifalarda siz sun'iy intellektdan birini tanlashni so'rashingiz mumkin WebPage, AboutPage, ContactPageQo'shish page yilda bpcab_ai_schema_allowed_post_types() va buyruq satrini sozlang.

Nima uchun mening diagrammam Elementor sahifasida ko'rinmaydi?

Ko'pincha siz oldindan ko'rish yoki shablonni sinab ko'rayotganingiz uchun, a emas is_singular() classic. Yakuniy ommaviy URL manzilini sinab ko'ring, keyin manbasini tekshiring. Agar kontent post_content tomonida "bo'sh" bo'lsa, quyidagiga asoslangan "rendered text" variantidan foydalaning. apply_filters('the_content', ...).

Tasdiqlash uchun diagrammani administrator panelida ko'rsata olamanmi?

Ha. JSON faylini ko'rsatadigan faqat o'qish uchun metaboks qo'shing. Ushbu maydonni tahrirlash mumkin bo'lgan qilib qo'ymang, aks holda siz tasdiqlash ustidan nazoratni yo'qotasiz.

Agar API ba'zan noto'g'ri JSON qaytarsa, nima qilishim kerak?

Kamaytirish temperatureSo'rovni yaxshilang ("faqat JSON obyekti bilan javob bering") va validatsiyani PHP tomonida saqlang. Ishlab chiqarishda men buzilgan sxemadan ko'ra "sxemasiz" ni afzal ko'raman.

2000 ta maqolasi bo'lgan eski veb-saytni qanday ko'chirish mumkin?

2000 ta zaxira nusxasini ishga tushirmang. Zaxira nusxalarini paketlarda (50 ta post) qayta ishlaydigan, pauza bilan ishlaydigan va tezlik chegarasini hisobga oladigan WP-CLI buyrug'ini yoki paket skriptini qo'shing. Agar xohlasangiz, men sizga WP-CLI versiyasini quyidagiga asoslangan holda taqdim eta olaman. WP_CLI::add_command() ushbu plagin uchun moslashtirilgan.