18 β Email, HTTP API va keshlash¶
β¬ οΈ Oldingi: 17 β WP-Cron va fon vazifalari Β· π README Β· Keyingi: 19 β Blok muharririga kirish va create-block β‘οΈ
Bu bobda: plugin'ingiz tashqi dunyo bilan qanday "gaplashishini" o'rganamiz β
wp_mail()bilan (HTML email,From/Reply-Toheader,wp_mail_content_typefilter, va nega yetkazib berish ishonchsiz, SMTP plugin tavsiyasi),wp_remote_get()/wp_remote_post()/wp_remote_request()bilan tashqi API'gacurlo'rniga WordPress'cha xavfsiz so'rov yuborish, javobniwp_remote_retrieve_body/wp_remote_retrieve_response_codebilan o'qibis_wp_errorvaWP_Errororqali xatoni to'g'ri ushlash, hamda tashqi API natijasini har so'rovda qayta tortmaslik uchun Transients (10-bob) bilan keshlash naqshini β "Kitoblar katalogi" plugin'imizga tashqi kitob API'sidan ma'lumot olib keshlash va yangi kitob qo'shilganda admin'ga email yuborishni qo'shib amalda qilib chiqamiz.
Muammo: plugin saytdan tashqariga chiqishi kerak¶
"Kitoblar katalogi" plugin'imiz hozircha o'z ichida yopiq: CPT, taxonomiya, meta, o'z jadval, REST endpoint β barchasi sayt ichida. Lekin haqiqiy plugin'lar deyarli har doim tashqi dunyo bilan bog'lanadi:
- Yangi kitob qo'shilganda sayt egasiga email kelishi kerak ("Yangi kitob: 'PHP asoslari' qo'shildi").
- Kitobning narxi yoki muqovasini tashqi API'dan (masalan Open Library yoki o'zingizning katalog serveringizdan) olib kelmoqchisiz.
- Bu tashqi so'rov sekin (tarmoq orqali, 200-2000 ms) β uni har sahifa yuklanishida takrorlash saytni o'ldiradi, demak keshlash shart.
PHP'da bularni mail(), curl_* yoki file_get_contents('http://...') bilan qilish mumkin. Lekin WordPress'da bunday qilmang. WordPress o'zining qatlamlarini beradi: ular hooks bilan kengaytiriladi, proxy/SSL sozlamalarini hurmat qiladi, xatolarni WP_Error bilan birxil qaytaradi va xavfsizroq. Bu bob aynan shu uch qatlamni β email, HTTP, kesh β birga o'rgatadi, chunki ular ko'pincha bitta vazifada uchrashadi.
π Oltin qoida: WordPress ichida tashqi resurs bilan ishlaganda PHP'ning xom funksiyasini emas, WordPress'ning ekvivalentini ishlating: mail() emas wp_mail(), curl/file_get_contents emas wp_remote_*, har og'ir tashqi so'rovni transient bilan o'rang.
Email: wp_mail()¶
PHP'ning mail() funksiyasi qo'pol: header'lar bilan kurashasiz, xatoni bilmaysiz, plugin'lar aralasholmaydi. WordPress wp_mail() ni beradi β u ichida PHPMailer ustida ishlaydi va wp_mail filterlari orqali kengaytiriladi.
Rasmiy imzo (developer.wordpress.org bilan tasdiqlangan):
wp_mail(
string|string[] $to, // qabul qiluvchi(lar)
string $subject, // mavzu
string $message, // xat matni
string|string[] $headers = '', // qo'shimcha header'lar (ixtiyoriy)
string|string[] $attachments = [] // ilova fayllar (ixtiyoriy)
): bool // true = topshirildi, false = xato
β οΈ wp_mail() ning true qaytishi "yetkazib berildi" degani EMAS. U faqat xatni mail tizimiga topshirilganini anglatadi (PHP mail() yoki SMTP). Xat spam'ga tushishi yoki umuman yetib bormasligi mumkin β bu bobning oxirida shu haqida.
Eng oddiy email¶
$natija = wp_mail(
'admin@misol.uz',
'Yangi kitob qo\'shildi',
"Saytga yangi kitob qo'shildi. Tekshirib ko'ring."
);
if ( ! $natija ) {
// wp_mail false qaytardi -> mail tizimiga topshirilmadi
error_log( 'Kitoblar katalogi: email topshirilmadi' );
}
βΉοΈ $message β oddiy matn (plain text). Standart Content-Type β text/plain, shuning uchun bu yerda HTML teglari matn sifatida ko'rinadi, render qilinmaydi. HTML xat uchun pastdagi bo'limga qarang.
Header'lar: From, Reply-To, Cc, Bcc¶
Header'larni massiv sifatida berish eng tushunarli yo'l (har element β bitta header satri):
$headers = [
'From: Kitoblar katalogi <noreply@misol.uz>',
'Reply-To: Muallif <muallif@misol.uz>',
'Cc: muharrir@misol.uz',
];
wp_mail( 'admin@misol.uz', 'Yangi kitob', "Matn...", $headers );
π From header β xat kimdan kelgani. Agar bermasangiz, WordPress standart wordpress@<sizning-domeningiz> ni ishlatadi (ko'pincha mavjud bo'lmagan manzil β spam filtrlari yoqtirmaydi). To'g'ri From qo'yish yetkazib berishni yaxshilaydi. Reply-To β foydalanuvchi "Javob" bosganda qaysi manzilga ketishi.
π‘ From ni global o'zgartirmoqchi bo'lsangiz (har email uchun), header berish o'rniga wp_mail_from va wp_mail_from_name filterlaridan foydalaning β lekin bu butun saytga ta'sir qiladi, ehtiyot bo'ling.
HTML email¶
Ikki yo'l bor. Birinchi (afzal) β header orqali, faqat shu xatga ta'sir qiladi:
namespace Oqil\KitobKatalog;
function kitkat_html_email( string $to, string $subject, string $html ): bool {
$headers = [
'Content-Type: text/html; charset=UTF-8',
'From: Kitoblar katalogi <noreply@misol.uz>',
];
return wp_mail( $to, $subject, $html, $headers );
}
Ikkinchi β wp_mail_content_type filter. Bu global (filter qo'shilgan vaqtdagi har bir wp_mail'ga ta'sir qiladi), shuning uchun xatdan keyin darhol olib tashlang:
namespace Oqil\KitobKatalog;
function kitkat_html_email_filter( string $to, string $subject, string $html ): bool {
// 1) Content-Type ni text/html ga o'zgartiruvchi filterni qo'shamiz
$turi = static fn( string $content_type ): string => 'text/html';
add_filter( 'wp_mail_content_type', $turi );
// 2) Xatni yuboramiz
$natija = wp_mail( $to, $subject, $html );
// 3) Filterni DARHOL olib tashlaymiz -> keyingi xatlar yana text/plain
remove_filter( 'wp_mail_content_type', $turi );
return $natija;
}
β οΈ Agar wp_mail_content_type filterini olib tashlamasangiz, undan keyingi barcha email'lar (parol tiklash, izoh xabarnomalari) HTML deb yuboriladi va buzilib ko'rinishi mumkin. Shuning uchun header usuli (faqat bitta xatga ta'sir qiladi) ko'p hollarda xavfsizroq.
π HTML xatda matnni tayyorlaganda escape qiling. Foydalanuvchi kiritgan ma'lumot (kitob nomi, izoh) HTML'ga tushsa, esc_html() bilan tozalang β aks holda XSS yoki buzilgan razmetka chiqadi.
Plugin'imizga ulaymiz: yangi kitob qo'shilganda email¶
CPT bilan (07-bob) kitob post nashr qilinganda admin'ga xabar yuboramiz. publish_kitob hook'i (publish_{$post_type}) aynan shu post turi publish holatga o'tganda ishga tushadi:
namespace Oqil\KitobKatalog;
add_action( 'publish_kitob', __NAMESPACE__ . '\\yangi_kitob_email', 10, 2 );
function yangi_kitob_email( int $post_id, \WP_Post $post ): void {
// Faqat birinchi marta publish bo'lganda email kerak (qayta saqlashda emas).
// Oddiylik uchun bu yerda har publish'da yuboramiz; real holatda
// post_meta bilan "email yuborilgan" bayrog'ini qo'yish mumkin.
$admin_email = get_option( 'admin_email' ); // sayt admin manzili (WP core option)
$sarlavha = get_the_title( $post );
$subject = sprintf(
/* translators: %s: kitob nomi */
__( 'Yangi kitob qo\'shildi: %s', 'kitoblar-katalogi' ),
$sarlavha
);
// HTML xat matni β foydalanuvchi ma'lumotini esc_html bilan tozalaymiz
$html = sprintf(
'<h2>%1$s</h2><p>%2$s</p><p><a href="%3$s">%4$s</a></p>',
esc_html( $sarlavha ),
esc_html__( 'Saytga yangi kitob qo\'shildi.', 'kitoblar-katalogi' ),
esc_url( get_edit_post_link( $post_id, 'raw' ) ?? '' ),
esc_html__( 'Tahrirlash', 'kitoblar-katalogi' )
);
$headers = [
'Content-Type: text/html; charset=UTF-8',
'From: Kitoblar katalogi <noreply@' . wp_parse_url( home_url(), PHP_URL_HOST ) . '>',
];
wp_mail( $admin_email, $subject, $html, $headers );
}
β οΈ Halol eslatma: real email yuborilishi faqat ishlaydigan saytda ko'rinadi (mail serveri sozlangan bo'lsa). Yuqoridagi kod docs bilan tasdiqlangan va sintaktik to'g'ri, lekin natijani o'z saytingizda kuzating β masalan MailHog (lokal SMTP tutqich, wp-env'da ulanadi, 02-bob) yoki WP Mail Logging plugin'i bilan yuborilgan xatlarni ko'ring.
Nega email ko'pincha yetib bormaydi β SMTP plugin¶
Bu β yangi plugin yozuvchilarni kutilmaganda urib ketadigan masala. wp_mail() standart holatda PHP'ning mail() funksiyasidan foydalanadi, u esa serverning lokal sendmail dasturiga tayanadi. Ko'pchilik shared hosting va bulut serverlarida:
- Lokal
sendmailumuman sozlanmagan yoki o'chirilgan. - Xat yuborilsa ham,
Frommanzili domenga mos kelmaydi (SPF/DKIM yo'q) β Gmail/Outlook uni spamga tashlaydi yoki rad etadi.
Shuning uchun amaliyotda SMTP plugin ishlatiladi: u wp_mail() ni real SMTP server (SendGrid, Mailgun, Amazon SES, Gmail SMTP) orqali yuborishga ulaydi. Eng mashhuri β WP Mail SMTP.
π Siz plugin muallifi sifatida wp_mail() ni to'g'ri ishlatasiz (xolos) β SMTP'ni sayt egasi o'rnatadi. Sizning kodingiz o'zgarmaydi: WP Mail SMTP wp_mail qatlamiga ulanadi, sizning wp_mail() chaqiruvingiz avtomatik SMTP orqali ketadi. Bu β WordPress hook arxitekturasining go'zalligi.
π‘ Plugin hujjatingizda ("o'z saytingizda") sayt egasiga maslahat bering: "Email kelmasa, WP Mail SMTP kabi SMTP plugin o'rnating va to'g'ri From domenini sozlang."
HTTP API: tashqi serverga so'rov¶
Endi kitob ma'lumotini tashqi API'dan olamiz. PHP'da curl yoki file_get_contents ishlatardingiz β WordPress'da HTTP API bor. U bitta birxil interfeys ostida server muhitiga qarab curl, streams yoki boshqasini tanlaydi, proxy/timeout/SSL sozlamalarini hurmat qiladi va xatoni WP_Error bilan qaytaradi.
| Funksiya | Vazifa | Imzo |
|---|---|---|
wp_remote_get |
GET so'rov | wp_remote_get( $url, $args = [] ): array\|WP_Error |
wp_remote_post |
POST so'rov | wp_remote_post( $url, $args = [] ): array\|WP_Error |
wp_remote_request |
Ixtiyoriy metod ($args['method']) |
wp_remote_request( $url, $args = [] ): array\|WP_Error |
wp_remote_head |
HEAD so'rov | wp_remote_head( $url, $args = [] ): array\|WP_Error |
π‘ wp_remote_get/wp_remote_post β wp_remote_request ustidagi qulay o'ramlar (method ni o'zlari belgilaydi). Uchchovi ham bir xil javob qaytaradi.
β οΈ URL foydalanuvchidan kelsa, wp_remote_get o'rniga wp_safe_remote_get ishlating (SSRF himoyasi: ichki manzillarga so'rov yuborishni bloklaydi). Tashqi, o'zingiz biladigan API uchun wp_remote_get yetarli.
$args β so'rov parametrlari¶
Eng ko'p ishlatiladigan kalitlar (rasmiy hujjatdan):
| Kalit | Ma'no | Default |
|---|---|---|
timeout |
Necha sekund kutish | 5 |
headers |
So'rov header'lari (massiv) | [] |
body |
So'rov tanasi (string yoki massiv) | null |
method |
HTTP metod (wp_remote_request uchun) |
'GET' |
redirection |
Ruxsat etilgan redirect soni | 5 |
sslverify |
SSL sertifikat tekshiruvi | true |
π timeout ni ataylab qo'ying. Standart 5 sekund β agar tashqi API sekin bo'lsa, sizning saytingiz shu 5 sekund kutib turadi (foydalanuvchi sahifa yuklanishini kutadi). Shuning uchun: (a) timeout'ni oqilona qo'ying, (b) natijani keshlang (pastda), (c) iloji bo'lsa og'ir tashqi chaqiruvni WP-Cron (17-bob) fon vazifasiga o'tkazing.
Javobni o'qish va xatoni tekshirish¶
Bu β eng muhim qism. wp_remote_get ikki xil narsa qaytaradi: muvaffaqiyatda β massiv (headers, body, response kalitlari bilan), xatoda (tarmoq uzilishi, DNS, timeout) β WP_Error obyekti. Shuning uchun avval is_wp_error() bilan tekshiring, keyingina javobni o'qing.
namespace Oqil\KitobKatalog;
function kitkat_api_soro( string $url ): array|\WP_Error {
$javob = wp_remote_get( $url, [
'timeout' => 8,
'headers' => [
'Accept' => 'application/json',
'User-Agent' => 'KitoblarKatalogi/1.0; ' . home_url(),
],
] );
// 1) Tarmoq darajasidagi xato? (DNS, timeout, ulanish uzildi)
if ( is_wp_error( $javob ) ) {
// WP_Error'dan kod va xabarni olamiz
return $javob; // chaqiruvchiga WP_Error'ni qaytaramiz
}
// 2) HTTP status kodi β 200 oralig'idami?
$kod = wp_remote_retrieve_response_code( $javob ); // int|string
if ( 200 !== (int) $kod ) {
return new \WP_Error(
'kitkat_api_status',
sprintf(
/* translators: %d: HTTP status kodi */
__( 'API kutilmagan status qaytardi: %d', 'kitoblar-katalogi' ),
(int) $kod
),
[ 'status' => $kod ]
);
}
// 3) Tanani o'qiymiz va JSON'ni dekodlaymiz
$tana = wp_remote_retrieve_body( $javob ); // string (bo'sh bo'lishi mumkin)
$malumot = json_decode( $tana, true ); // assotsiativ massiv
if ( null === $malumot && JSON_ERROR_NONE !== json_last_error() ) {
return new \WP_Error(
'kitkat_api_json',
__( 'API noto\'g\'ri JSON qaytardi.', 'kitoblar-katalogi' )
);
}
return $malumot; // toza, dekodlangan massiv
}
π Uch darajali tekshiruv (yodda saqlang):
is_wp_error($javob)β tarmoq darajasi (so'rov umuman bormadi: DNS, timeout, ulanish). Buni o'tkazib yuboribwp_remote_retrieve_bodychaqirsangiz,WP_Error'ga bo'sh string qaytadi va xatoni payqamaysiz.wp_remote_retrieve_response_code()β HTTP darajasi (so'rov bordi, lekin server404/500/429qaytardi).200 OKekanini tekshiring.json_decode+json_last_error()β ma'lumot darajasi (server javob berdi, lekin tana buzuq yoki kutilgan format emas).
π‘ wp_remote_retrieve_body va wp_remote_retrieve_response_code WP_Error'ni ham xavfsiz qabul qiladi (is_wp_error bo'lsa bo'sh qiymat qaytaradi) β lekin bu sizni xatoni e'tibordan chetda qoldirmasin. Doim avval is_wp_error bilan ajrating.
WP_Error bilan ishlash¶
WP_Error β WordPress'ning standart xato obyekti (new WP_Error($code, $message, $data)). Undan ma'lumot olish:
$natija = kitkat_api_soro( 'https://api.misol.uz/kitob/123' );
if ( is_wp_error( $natija ) ) {
$kod = $natija->get_error_code(); // string|int: masalan 'kitkat_api_status'
$xabar = $natija->get_error_message(); // string: birinchi xato xabari
$data = $natija->get_error_data(); // mixed: uzatilgan qo'shimcha ma'lumot
error_log( "Kitoblar katalogi API xatosi [{$kod}]: {$xabar}" );
// Foydalanuvchiga: "Hozircha ma'lumot olib bo'lmadi, keyinroq urinib ko'ring."
} else {
// $natija β toza massiv, ishlatishimiz mumkin
}
π WP_Error naqshi WordPress bo'ylab izchil: wp_remote_*, register_rest_route callback'lari (16-bob), ko'p core funksiyalar xatoda WP_Error qaytaradi. Shuning uchun is_wp_error() β eng tez-tez ishlatiladigan tekshiruvlardan biri.
Keshlash: tashqi so'rovni har safar tortmaslik¶
Tasavvur qiling, kitob sahifasi har ochilganda tashqi API'ga so'rov ketadi. 8 sekundlik timeout, 500 ms javob, kuniga minglab ko'rish β bu falokat: sayt sekin, API rate-limit (429) qaytaradi, foydalanuvchi kutadi. Yechim β javobni transient (10-bob) bilan keshlash.
Naqsh oddiy va kuchli: avval keshdan o'qishga harakat qiling β bor bo'lsa qaytaring; yo'q bo'lsa tashqi so'rov yuboring va natijani keshga yozing.
namespace Oqil\KitobKatalog;
function kitkat_kitob_apidan( int $kitob_id ): array|\WP_Error {
// 1) Kesh kaliti β har kitobga alohida (transient nomi <= 172 belgi)
$kalit = 'kitkat_api_kitob_' . $kitob_id;
// 2) Avval keshni tekshiramiz (false !== bilan: bo'sh massivni ham hurmat qilamiz)
$kesh = get_transient( $kalit );
if ( false !== $kesh ) {
return $kesh; // KESH HIT -> tashqi so'rovsiz, tez
}
// 3) KESH MISS -> tashqi API'ga so'rov
$url = sprintf( 'https://api.misol.uz/kitob/%d', $kitob_id );
$natija = kitkat_api_soro( $url ); // yuqoridagi funksiya: massiv yoki WP_Error
// 4) Xato bo'lsa -> KESHLAMAYMIZ (yoki qisqa muddatga), shunda keyingi
// so'rovda qayta urinish imkoni qoladi. Xatoni qaytaramiz.
if ( is_wp_error( $natija ) ) {
// Ixtiyoriy: "negativ kesh" -> qisqa muddatga xatoni eslab, API'ni bombardimon
// qilmaslik. Bu yerda 1 daqiqaga.
set_transient( $kalit, $natija, MINUTE_IN_SECONDS );
return $natija;
}
// 5) Muvaffaqiyat -> natijani 6 soatga keshlaymiz
set_transient( $kalit, $natija, 6 * HOUR_IN_SECONDS );
return $natija;
}
π Kesh muddatini ma'lumot "yangilik darajasi"ga qarab tanlang. Kitob narxi tez o'zgarsa β 30 daqiqa; tavsif/muqova kam o'zgarsa β 6-24 soat. WordPress konstantalaridan foydalaning: MINUTE_IN_SECONDS, HOUR_IN_SECONDS, DAY_IN_SECONDS.
β οΈ get_transient qaytaruvini doim false !== $kesh bilan tekshiring, if ( $kesh ) emas. Aks holda keshlangan bo'sh massiv yoki 0 "yo'q" deb hisoblanib, har safar tashqi so'rov ketadi β kesh ishlamaydi.
π‘ Negativ kesh (4-qadam) β nozik, lekin foydali: tashqi API uzilganda xatoni qisqa muddatga (1 daqiqa) eslab, har sahifa yuklanishida o'lik API'ga urilmaslik. Aks holda API down bo'lsa, sizning saytingiz ham har so'rovda 8 sekund kutadi.
Object cache va transient β qaysi birini?¶
10-bobda ko'rgan farqni eslang:
- Transient (
set_transient/get_transient) β doimiy (persistent). Object cache (Redis/Memcached) bo'lsa xotira-keshda, bo'lmasawp_optionsjadvalida saqlanadi. Server qayta ishga tushsa ham qoladi. Tashqi API natijasi uchun deyarli har doim shu to'g'ri tanlov β minutlar/soatlar davom etishi kerak. - Object cache (
wp_cache_set/wp_cache_get) β persistent backend bo'lmasa, faqat bitta so'rov davomida yashaydi. Bitta sahifa yuklanishida bir necha marta kerak bo'ladigan, lekin keyingi so'rovda yangilanaversa ham mayli bo'lgan ma'lumot uchun.
π Tashqi HTTP natijasi sekin va so'rovlar orasida ham foydali β transient ishlating. Object cache faqat bitta so'rov ichidagi takror hisoblashlarni tejaydi.
β οΈ Halol eslatma: kesh HIT/MISS, real HTTP javoblari va object cache mavjudligi faqat ishlaydigan saytda ko'rinadi. Yuqoridagi mantiq docs bilan tasdiqlangan va to'g'ri yozilgan β o'z saytingizda Query Monitor plugin'i bilan HTTP API chaqiruvlarini va so'rovlar sonini kuzating (26-bob): kesh ishlasa, ikkinchi sahifa yuklanishida tashqi so'rov yo'qoladi.
Birga qo'yamiz: to'liq servis sinfi¶
Endi email, HTTP va keshni bitta toza sinfga yig'amiz β "Kitoblar katalogi" plugin'imizning tashqi-aloqa qatlami:
// kitoblar-katalogi/includes/class-tashqi-servis.php
namespace Oqil\KitobKatalog;
class TashqiServis {
/** Tashqi API'dan kitob ma'lumotini (keshlangan) oladi. */
public static function kitob_malumoti( int $kitob_id ): array|\WP_Error {
$kalit = 'kitkat_api_kitob_' . $kitob_id;
$kesh = get_transient( $kalit );
if ( false !== $kesh ) {
return $kesh;
}
$javob = wp_remote_get(
sprintf( 'https://api.misol.uz/kitob/%d', $kitob_id ),
[
'timeout' => 8,
'headers' => [ 'Accept' => 'application/json' ],
]
);
if ( is_wp_error( $javob ) ) {
set_transient( $kalit, $javob, MINUTE_IN_SECONDS ); // negativ kesh
return $javob;
}
$kod = (int) wp_remote_retrieve_response_code( $javob );
if ( 200 !== $kod ) {
return new \WP_Error( 'kitkat_status', "API status: {$kod}", [ 'status' => $kod ] );
}
$malumot = json_decode( wp_remote_retrieve_body( $javob ), true );
if ( ! is_array( $malumot ) ) {
return new \WP_Error( 'kitkat_json', 'Noto\'g\'ri JSON' );
}
set_transient( $kalit, $malumot, 6 * HOUR_IN_SECONDS );
return $malumot;
}
/** Yangi kitob publish bo'lganda admin'ga HTML email yuboradi. */
public static function publish_xabar( int $post_id, \WP_Post $post ): void {
$headers = [
'Content-Type: text/html; charset=UTF-8',
'From: Kitoblar katalogi <noreply@' . wp_parse_url( home_url(), PHP_URL_HOST ) . '>',
];
$html = sprintf(
'<h2>%s</h2><p>%s</p>',
esc_html( get_the_title( $post ) ),
esc_html__( 'Saytga yangi kitob qo\'shildi.', 'kitoblar-katalogi' )
);
wp_mail(
get_option( 'admin_email' ),
esc_html__( 'Yangi kitob qo\'shildi', 'kitoblar-katalogi' ),
$html,
$headers
);
}
/** Hook'larni ulaydi. */
public static function boshla(): void {
add_action( 'publish_kitob', [ self::class, 'publish_xabar' ], 10, 2 );
}
}
Asosiy plugin faylida: \Oqil\KitobKatalog\TashqiServis::boshla();.
π‘ Bu sinf uch g'oyani birlashtiradi: (1) wp_mail to'g'ri header bilan, (2) wp_remote_get uch darajali xato tekshiruvi bilan, (3) transient keshi (musbat + negativ). Aynan shu β ishonchli plugin'ning tashqi-aloqa qatlami.
Xulosa¶
- Email:
wp_mail($to, $subject, $message, $headers, $attachments). HTML uchunContent-Type: text/htmlheader (afzal) yokiwp_mail_content_typefilter (global β darhol olib tashlang).From/Reply-Toheader yetkazib berishni yaxshilaydi.true= topshirildi (yetkazildi emas) β ishonchli yetkazish uchun sayt egasi SMTP plugin (WP Mail SMTP) o'rnatadi, sizning kodingiz o'zgarmaydi. - HTTP API:
wp_remote_get/wp_remote_post/wp_remote_requestβcurl/file_get_contentso'rniga.$argsdatimeout/headers/body. Uch darajali xato tekshiruvi:is_wp_error->wp_remote_retrieve_response_code->json_decode/json_last_error. XatoniWP_Errorbilan birxil qaytaring. - Keshlash: har og'ir tashqi so'rovni transient bilan o'rang β
get_transient(false !==bilan) -> bor bo'lsa qaytar :wp_remote_get->set_transient. Musbat va negativ kesh. Tashqi API uchun transient (object cache emas).
Keyingi bobda butunlay yangi olamga β Gutenberg blok muharririga kiramiz: @wordpress/create-block bilan birinchi blokimizni scaffold qilamiz.
18-bob mashqlari¶
Oson¶
- (Oson)
wp_mail()ning beshta parametrini tartibi bilan yozing va har birining tipini ayting. Funksiya nima qaytaradi va bu qaytaruv "yetkazib berildi" deganimi? - (Oson) Admin manziliga ("Salom") mavzuli oddiy matnli email yuboruvchi bitta
wp_mail()chaqiruvi yozing. Admin manzilini qaysi funksiya/option'dan olasiz? - (Oson) HTML email yuborishning ikki yo'lini ayting. Nima uchun header usuli
wp_mail_content_typefilteridan ko'pincha xavfsizroq? - (Oson)
wp_remote_get('https://misol.uz/data')chaqiring va javobning tarmoq xatosimi ekanini tekshiruvchiifyozing. Qaysi funksiya bilan tekshirasiz? - (Oson)
wp_remote_retrieve_bodyvawp_remote_retrieve_response_codenima qaytaradi (tip)? Ulardan oldin negais_wp_errortekshirilishi kerak? - (Oson) Tashqi API natijasini keshlash uchun transient kalitini yozing (har kitobga alohida). Transient nomi necha belgidan oshmasligi kerak?
O'rta¶
- (O'rta)
from/reply-toheader'li vaContent-Type: text/htmlli email yuboruvchi funksiya yozing.Frommanzilini sayt domenidan quring. - (O'rta)
wp_remote_getgatimeout,headers(Accept: application/json) va 8 sekundlik kutish bilan$argsbering. Nima uchuntimeoutni ataylab qo'yish muhim? - (O'rta)
wp_remote_getjavobidan HTTP status kodini oling va200emasligini tekshiribWP_Errorqaytaring.WP_Errorkonstruktorining uch argumenti nima? - (O'rta)
wp_mail_content_typefilterini qo'shib, email yuborib, keyin filterni olib tashlovchi to'liq funksiya yozing. Nega olib tashlash shart?
Qiyin¶
-
(Qiyin) Tashqi API'dan kitob ma'lumotini olib 6 soatga keshlaydigan funksiya yozing: avval transient'dan o'qisin, kesh bo'lmasa
wp_remote_getqilsin, uch darajali xato tekshiruvini (is_wp_error-> status kodi -> JSON) bajarsin va muvaffaqiyatda natijani keshlasin.Yechim
namespace Oqil\KitobKatalog; function kitob_apidan( int $kitob_id ): array|\WP_Error { $kalit = 'kitkat_api_kitob_' . $kitob_id; // 1) Kesh (false !== bilan, bo'sh massivni ham hurmat qilamiz) $kesh = get_transient( $kalit ); if ( false !== $kesh ) { return $kesh; // KESH HIT } // 2) KESH MISS -> tashqi so'rov $javob = wp_remote_get( sprintf( 'https://api.misol.uz/kitob/%d', $kitob_id ), [ 'timeout' => 8, 'headers' => [ 'Accept' => 'application/json' ] ] ); // 3a) Tarmoq xatosi if ( is_wp_error( $javob ) ) { return $javob; } // 3b) HTTP status $kod = (int) wp_remote_retrieve_response_code( $javob ); if ( 200 !== $kod ) { return new \WP_Error( 'kitkat_status', "API status: {$kod}", [ 'status' => $kod ] ); } // 3c) JSON $malumot = json_decode( wp_remote_retrieve_body( $javob ), true ); if ( ! is_array( $malumot ) ) { return new \WP_Error( 'kitkat_json', 'Noto\'g\'ri JSON javob' ); } // 4) Muvaffaqiyat -> keshlash set_transient( $kalit, $malumot, 6 * HOUR_IN_SECONDS ); return $malumot; }Tushuntirish: uch darajali tekshiruv tartibi muhim β
is_wp_error(tarmoq) eng avval, chunki keyingiwp_remote_retrieve_*funksiyalariWP_Error'ga bo'sh qiymat qaytaradi va xatoni yashiradi.false !== $keshkeshlangan bo'sh massivni "yo'q" deb hisoblamaslik uchun. Muvaffaqiyat 6 soatga keshlanadi; xato keshlanmaydi (keyingi so'rovda qayta urinish imkoni qoladi). -
(Qiyin)
wp_remote_postbilan tashqi API'ga JSON tana yuboruvchi funksiya yozing:Content-Type: application/jsonheader,bodyniwp_json_encodebilan kodlang, javobni dekodlang.Yechim
namespace Oqil\KitobKatalog; function kitob_apiga_yubor( array $payload ): array|\WP_Error { $javob = wp_remote_post( 'https://api.misol.uz/kitob', [ 'timeout' => 10, 'headers' => [ 'Content-Type' => 'application/json' ], 'body' => wp_json_encode( $payload ), // massivni JSON'ga ] ); if ( is_wp_error( $javob ) ) { return $javob; } $kod = (int) wp_remote_retrieve_response_code( $javob ); if ( $kod < 200 || $kod >= 300 ) { return new \WP_Error( 'kitkat_post', "POST muvaffaqiyatsiz: {$kod}" ); } $natija = json_decode( wp_remote_retrieve_body( $javob ), true ); return is_array( $natija ) ? $natija : []; }Tushuntirish:
wp_remote_postbodyni POST tanasi sifatida yuboradi. JSON yuborgandaContent-Type: application/jsonheader SHART, aks holda server tanani form-data deb o'qiydi.wp_json_encodeβ WordPress'ning xavfsiz JSON kodlash o'ramidir. Status2xxoralig'ini tekshiramiz (POST'da201 Createdham normal). -
(Qiyin) Yangi
kitobpublish bo'lganda admin'ga HTML email yuboruvchi to'liq hook + funksiya yozing. Kitob nominiesc_htmlbilan tozalang,Fromheader bering, tahrirlash havolasini qo'shing.Yechim
namespace Oqil\KitobKatalog; add_action( 'publish_kitob', __NAMESPACE__ . '\\kitob_publish_email', 10, 2 ); function kitob_publish_email( int $post_id, \WP_Post $post ): void { $nom = get_the_title( $post ); $tahrir = get_edit_post_link( $post_id, 'raw' ) ?? ''; $headers = [ 'Content-Type: text/html; charset=UTF-8', 'From: Kitoblar katalogi <noreply@' . wp_parse_url( home_url(), PHP_URL_HOST ) . '>', ]; $html = sprintf( '<h2>%1$s</h2><p>%2$s</p><p><a href="%3$s">%4$s</a></p>', esc_html( $nom ), esc_html__( 'Saytga yangi kitob qo\'shildi.', 'kitoblar-katalogi' ), esc_url( $tahrir ), esc_html__( 'Tahrirlash', 'kitoblar-katalogi' ) ); wp_mail( get_option( 'admin_email' ), esc_html__( 'Yangi kitob qo\'shildi', 'kitoblar-katalogi' ), $html, $headers ); }Tushuntirish:
publish_kitobβpublish_{$post_type}hook'i,kitobCPT publish bo'lganda ishlaydi.WP_Postikkinchi argument (accepted_args=2). HTML xat uchunContent-Typeheader.esc_html/esc_urlfoydalanuvchi ma'lumotini tozalaydi (XSS himoyasi). Email faqat ishlaydigan saytda real yuboriladi β lokalda MailHog bilan kuzating. -
(Qiyin) Negativ kesh qo'shing: tashqi API xato qaytarsa, xatoni 1 daqiqaga keshlab, API uzilganda har so'rovda qayta urinmaslik. 11-mashq yechimini shu bilan kengaytiring.
Yechim
namespace Oqil\KitobKatalog; function kitob_apidan_negativ( int $kitob_id ): array|\WP_Error { $kalit = 'kitkat_api_kitob_' . $kitob_id; $kesh = get_transient( $kalit ); if ( false !== $kesh ) { return $kesh; // HIT: musbat YOKI keshlangan WP_Error } $javob = wp_remote_get( sprintf( 'https://api.misol.uz/kitob/%d', $kitob_id ), [ 'timeout' => 8 ] ); // Xatoni QISQA muddatga keshlaymiz -> o'lik API'ni bombardimon qilmaymiz if ( is_wp_error( $javob ) ) { set_transient( $kalit, $javob, MINUTE_IN_SECONDS ); return $javob; } $kod = (int) wp_remote_retrieve_response_code( $javob ); if ( 200 !== $kod ) { $xato = new \WP_Error( 'kitkat_status', "API status: {$kod}" ); set_transient( $kalit, $xato, MINUTE_IN_SECONDS ); return $xato; } $malumot = json_decode( wp_remote_retrieve_body( $javob ), true ); if ( ! is_array( $malumot ) ) { return new \WP_Error( 'kitkat_json', 'Noto\'g\'ri JSON' ); } // Muvaffaqiyat -> uzoq muddat set_transient( $kalit, $malumot, 6 * HOUR_IN_SECONDS ); return $malumot; }Tushuntirish:
WP_Errorham serializatsiya qilinadigan obyekt, shuning uchun uni transient'ga saqlash mumkin. Xato 1 daqiqaga keshlanadi: API down bo'lsa, keyingi 60 sekund davomida sayt tashqi so'rov yubormaydi (8stimeout'da osilmaydi), 1 daqiqadan keyin avtomatik qayta uriniladi. Bu β "circuit breaker"ning sodda ko'rinishi. Diqqat:get_transientHIT bo'lsa qaytgan qiymatWP_Errorbo'lishi mumkin β chaqiruvchi baribiris_wp_errorbilan tekshiradi. -
(Qiyin) Sof-PHP funksiya yozing (WordPress'siz ishlaydi): JSON string'ni qabul qilib, dekodlab, agar
pricekaliti bo'lsa unifloatqilib qaytarsin, aks holdanull. Buniphp -rbilan haqiqatan ishga tushirib tekshiring.Yechim
function narxni_ajrat( string $json ): ?float { $data = json_decode( $json, true ); if ( ! is_array( $data ) || ! isset( $data['price'] ) ) { return null; } return (float) $data['price']; } // Test (php -r bilan ishlaydi, WP kerak emas): var_dump( narxni_ajrat( '{"price": "49.90"}' ) ); // float(49.9) var_dump( narxni_ajrat( '{"title": "PHP"}' ) ); // NULL var_dump( narxni_ajrat( 'buzuq json' ) ); // NULLTushuntirish: bu funksiya WordPress funksiyalariga tayanmaydi β
json_decodesof PHP. Shuning uchun uniphp -ryoki faylga yozibphpbilan haqiqatan ishga tushirish mumkin (HTTP qatlami βwp_remote_getβ esa WordPress'ni talab qiladi, faqatphp -lbilan tekshiriladi). Yomon JSONjson_decodenullqaytaradi,is_arraytekshiruvi uni ushlaydi. Bu β keshlangan API javobini parslashning izolyatsiya qilingan, testlanadigan qismi.
β¬ οΈ Oldingi: 17 β WP-Cron va fon vazifalari Β· π README Β· Keyingi: 19 β Blok muharririga kirish va create-block β‘οΈ