21 β Dynamic blok va PHP-only registratsiya¶
β¬ οΈ Oldingi: 20 β Static blok: edit, save, attributes Β· π README Β· Keyingi: 22 β Blok variations, styles, InnerBlocks, patterns β‘οΈ
Bu bobda: dynamic (dinamik) blokni 0 dan to'liq quramiz β static blokdan farqli ravishda HTML
post_contentga muzlatilmaydi, balki har so'rovda server tomonidarender.phporqali qaytadan hisoblanadi (o'zgaruvchan ma'lumot, masalan "so'nggi 5 kitob" uchun);block.jsondagi"render": "file:./render.php"(afzal yo'l) va muqobilregister_block_type(..., ['render_callback' => ...])ni,saveningnullqaytarishi (yoki umuman bo'lmasligi)ni,render.phpga ochiq$attributes/$content/$block(WP_Block) o'zgaruvchilarini,get_block_wrapper_attributes()wrapperini,WP_Querybilan ma'lumot olib kontekst bo'yicha escape qilishni, muharrirda natijani ko'rsatuvchiServerSideRender(@wordpress/server-side-render) komponentini, hamda PHP-only blok registratsiya (faqatblock.json+render.php, JS build'siz β sodda server bloklar uchun) usulini o'rganamiz va izchil namuna plugin'imizga "So'nggi kitoblar" dynamic blokini qo'shamiz.
Muammo: ma'lumot doim o'zgaradi¶
20-bobda "Kitob kartasi" static blokini yozdik. U a'lo ishlaydi β chunki kartadagi ma'lumot (kitob nomi, muallif) bir marta kiritiladi va o'zgarmaydi. save() HTML ni post_content ga muzlatadi, sahifa ochilganda PHP hech narsa hisoblamaydi: tez va sodda.
Endi boshqa vazifa. Bloggerimiz har sahifaga "Eng so'nggi qo'shilgan 5 ta kitob" ro'yxatini chiqarmoqchi. Muammo aniq: bu ro'yxat vaqt o'tishi bilan o'zgaradi. Bugun yangi kitob (07-bobdagi CPT) qo'shsangiz β ertaga ro'yxat boshqacha bo'lishi kerak. Lekin static blok HTML ni saqlash payti muzlatadi: blok joylashtirilgan kungi 5 ta kitob u yerda abadiy qotib qoladi. Yangi kitob qo'shsangiz ham eski ro'yxat ko'rinaveradi.
Yechim β dynamic blok: HTML ni saqlash payti emas, balki har so'rovda (sahifa ochilganda) PHP qayta hisoblaydi. Foydalanuvchi blokni bir marta joylashtiradi, ammo ro'yxat doim joriy ma'lumotni ko'rsatadi.
π Tub farq β HTML qayerda hisoblanadi. Static: save() HTML ni post_content ga yozadi (muzlatadi). Dynamic: save() null qaytaradi, HTML ni render.php har so'rovda qaytadan ishlab chiqaradi.
Static vs dynamic: qachon qaysi?¶
Tanlov ma'lumotning tabiatiga bog'liq, dizayniga emas.
| Static blok (20-bob) | Dynamic blok (bu bob) | |
|---|---|---|
| HTML qayerda | post_content (DB matni) |
har so'rovda render.php |
save() |
HTML qaytaradi | null (yoki yo'q) |
| Frontend ish | PHP hisoblamaydi (tez) | PHP har so'rovda ishlaydi |
| Ma'lumot | o'zgarmas | o'zgaruvchan / tashqi |
| "Block validation" xatosi | bo'lishi mumkin (save muzlatilgan) |
YO'Q (save bo'sh) |
| Misol | kitob kartasi, iqtibos | so'nggi kitoblar, hisoblagich |
- Static tanlang, agar ma'lumot bir marta kiritilsa va o'zgarmasa: kitob kartasi, ogohlantirish qutisi, iqtibos, qo'lda yozilgan bo'lim. Tezroq (PHP frontda hisoblamaydi) va serverga yuk kam.
- Dynamic tanlang, agar ma'lumot vaqt o'tishi bilan yoki boshqa joydan o'zgarsa: so'nggi postlar/kitoblar, foydalanuvchi ma'lumoti, hisoblagich, narx, ob-havo, REST'dan kelgan ma'lumot. Ma'lumotni bitta joyda (DB, CPT) saqlab, har so'rovda yangi ko'rsatasiz.
π‘ Yana bir afzallik: validation muammosi yo'q. Dynamic blokda save() null bo'lgani uchun WordPress saqlangan markupni joriy save() bilan taqqoslamaydi β 20-bobdagi "block validation" xatosi (markup mos kelmasligi) umuman bo'lmaydi. Markup'ni o'zgartirsangiz, render.php ni o'zgartirasiz, vassalom. Shuning uchun murakkab yoki tez-tez yangilanadigan ko'rinish uchun dynamic ko'pincha soddaroq ham bo'ladi.
β οΈ Lekin tekin emas. Dynamic blok har sahifa so'rovida render.php ni ishga tushiradi (WP_Query ham qiladi). Static esa tayyor HTML ni o'qiydi. Shuning uchun "o'zgarmas" ma'lumotni dynamic qilish β keraksiz server yuki. Avval "ma'lumot haqiqatan o'zgaradimi?" deb so'rang.
Dynamic blokni ro'yxatdan o'tkazish: ikki yo'l¶
Dynamic blok HTML ni render.php (yoki bir callback funksiya) orqali server tomonida hisoblaydi. WordPress'ga "render mantig'i qayerda" deb ikki usulda aytasiz.
1-yo'l (afzal): block.json dagi "render"¶
block.json ga bir qator qo'shasiz:
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "oqil/songgi-kitoblar",
"title": "So'nggi kitoblar",
"category": "widgets",
"icon": "book-alt",
"textdomain": "kitoblar-katalogi",
"editorScript": "file:./index.js",
"render": "file:./render.php"
}
"render": "file:./render.php" β WordPress shu faylni har frontend so'rovida ishga tushiradi va natijasini blok HTML'i sifatida ishlatadi.
βΉοΈ Bu qiymat file: prefiksli yo'l (developer.wordpress.org Block Metadata hujjatida tasdiqlangan). render.php build/ papkaga ham nusxalanadi (@wordpress/scripts --webpack-copy-php bilan), shuning uchun register_block_type( __DIR__ . '/build/songgi-kitoblar' ) uni topadi.
π save YO'Q. Dynamic blok index.js da faqat edit registratsiya qiladi (save umuman berilmaydi yoki () => null). HTML ni render.php ishlab chiqargani uchun save() ga ehtiyoj yo'q.
import { registerBlockType } from '@wordpress/blocks';
import Edit from './edit';
import metadata from './block.json';
registerBlockType( metadata.name, {
edit: Edit,
// save yo'q β dynamic blok HTML ni render.php dan oladi
} );
2-yo'l (muqobil): render_callback¶
block.json dagi "render" o'rniga (yoki block.json'siz eski uslubda) PHP'da callback berasiz:
namespace Oqil\KitobKatalog;
add_action( 'init', __NAMESPACE__ . '\\register_callback_blok' );
function register_callback_blok(): void {
register_block_type(
__DIR__ . '/build/songgi-kitoblar',
array(
'render_callback' => __NAMESPACE__ . '\\render_songgi_kitoblar',
)
);
}
function render_songgi_kitoblar( array $attributes, string $content, \WP_Block $block ): string {
// HTML stringni QAYTARING (echo qilmang)
return '<p ' . get_block_wrapper_attributes() . '>'
. esc_html__( 'So\'nggi kitoblar', 'kitoblar-katalogi' ) . '</p>';
}
βΉοΈ render_callback developer.wordpress.org dynamic-blocks qo'llanmasida tasdiqlangan: callback $attributes, $content argumentlarini oladi (uchinchi argument β WP_Block instansiyasi) va HTML stringni qaytaradi.
β οΈ render.php echo qiladi, render_callback return qiladi. render.php ichida output to'g'ridan-to'g'ri bosib chiqariladi (echo/?>...<?php). render_callback funksiyasi esa HTML stringni qaytaradi (return) β echo qilsa, blok o'rni noto'g'ri chiqadi. Ikki mexanizm, ikki qoida.
π‘ Qaysi birini tanlash? Yangi loyiha β block.json "render" (toza, deklarativ, fayl alohida). render_callback β kod dinamik bo'lsa (callback nomi shartli aniqlanadi) yoki bir blokni bir nechta marta turli render bilan ro'yxatdan o'tkazsangiz kerak bo'ladi. Ikkalasi bir vaqtda berilsa, render_callback ustun keladi.
render.php ichida nima bor?¶
render.php β oddiy PHP fayl. WordPress uni ishga tushirayotganda uchta o'zgaruvchini avtomatik ochadi (siz e'lon qilmaysiz):
| O'zgaruvchi | Tip | Nima |
|---|---|---|
$attributes |
array |
blok atributlari (block.json dagi attributes, joriy qiymatlar bilan) |
$content |
string |
blokning ichki kontenti (InnerBlocks bo'lsa β 22-bob) |
$block |
WP_Block |
blok instansiyasi (kontekst, $block->context va h.k.) |
βΉοΈ Bu uch o'zgaruvchi developer.wordpress.org Block Metadata hujjatida aynan shunday hujjatlangan: "$attributes (array): The block attributes. $content (string): The block default content. $block (WP_Block): The block instance." Scaffold qilingan render.php ham aynan shu izohni o'z ichiga oladi.
get_block_wrapper_attributes(): wrapper¶
Static blokda useBlockProps.save() eng tashqi elementga yadro class, id, rang, bo'shliq atributlarini qo'shardi. render.php da JS yo'q β buning PHP ekvivalenti get_block_wrapper_attributes(). U tayyor, escape qilingan atribut stringini qaytaradi:
βΉοΈ Signatura developer.wordpress.org bilan tasdiqlangan: get_block_wrapper_attributes( string[] $extra_attributes = array() ): string. Natija β class="wp-block-oqil-songgi-kitoblar ..." style="..." kabi allaqachon escape qilingan HTML atributlar stringi. Shuning uchun uni echo qilasiz, qaytadan escape qilmaysiz.
π Eng tashqi elementga get_block_wrapper_attributes() bering. Busiz supports (rang, bo'shliq, tekislash) qiymatlari markupga tushmaydi va frontend stili buziladi β bu render.php dagi eng ko'p uchraydigan kamchilik. Qo'shimcha atribut kerak bo'lsa massiv beriladi: get_block_wrapper_attributes( [ 'class' => 'kitkat-songgi' ] ) (yadro class'lari bilan birlashadi, ustiga yozmaydi).
Output escape β bu yerda ham SHART¶
render.php β sof PHP HTML chiqaradi (JSX'ning avtomatik escape'i YO'Q). Shuning uchun 12-bobdagi qoida to'liq kuchda: har bir o'zgaruvchini kontekst bo'yicha escape qiling.
- Matn β
esc_html() - HTML atribut β
esc_attr() - URL β
esc_url() - Ruxsat berilgan HTML (post kontenti) β
wp_kses_post() - Tarjima + escape β
esc_html__(),esc_html_e()
β οΈ render.php da escape unutilsa β XSS. $attributes foydalanuvchidan keladi (muharrir orqali) va WP_Query natijasi ham ishonchli emas (sarlavhada teg bo'lishi mumkin). Hech qachon echo $attributes['janr'] qilmang β echo esc_html( $attributes['janr'] ).
Muharrirda ko'rinish: ServerSideRender¶
Static blokda edit() JSX bilan blok ko'rinishini muharrirda o'zi chizardi. Dynamic blokda esa "haqiqiy" HTML faqat serverda (render.php) hosil bo'ladi β muharrir uni qanday ko'rsatadi?
Eng oddiy yo'l β ServerSideRender komponenti (@wordpress/server-side-render paketi). U render.php ni REST orqali serverga yuborib chaqiradi va natijasini muharrirda ko'rsatadi β ya'ni muharrirda ham frontenddagi bilan bir xil ko'rinadi.
import { __ } from '@wordpress/i18n';
import { useBlockProps, InspectorControls } from '@wordpress/block-editor';
import { PanelBody, TextControl, RangeControl } from '@wordpress/components';
import ServerSideRender from '@wordpress/server-side-render';
export default function Edit( { attributes, setAttributes } ) {
const { janr, soni } = attributes;
const blockProps = useBlockProps();
return (
<>
<InspectorControls>
<PanelBody title={ __( 'Ro\'yxat sozlamalari', 'kitoblar-katalogi' ) }>
<TextControl
label={ __( 'Janr slug (bo\'sh = barchasi)', 'kitoblar-katalogi' ) }
value={ janr }
onChange={ ( v ) => setAttributes( { janr: v } ) }
/>
<RangeControl
label={ __( 'Nechta kitob', 'kitoblar-katalogi' ) }
value={ soni }
onChange={ ( v ) => setAttributes( { soni: v } ) }
min={ 1 }
max={ 10 }
/>
</PanelBody>
</InspectorControls>
<div { ...blockProps }>
<ServerSideRender
block="oqil/songgi-kitoblar"
attributes={ attributes }
/>
</div>
</>
);
}
blockβ blok nomi (block.jsondaginamebilan bir xil).attributesβ joriy atributlar; o'zgartirilsa,ServerSideRenderrender.phpni qayta chaqiradi (yangi natija ko'rinadi).
βΉοΈ ServerSideRender importi va ishlatilishi developer.wordpress.org dynamic-blocks qo'llanmasida tasdiqlangan: import ServerSideRender from '@wordpress/server-side-render'; va <ServerSideRender block="..." attributes={ ... } />.
π‘ ServerSideRender β sodda, lekin kamtarona. U render.php ni REST orqali chaqiradi, demak har atribut o'zgarganda server so'rovi ketadi (sekinroq) va muharrirda interaktivlik (RichText kabi) bo'lmaydi β faqat tayyor HTML ko'rsatiladi. Murakkab muharrir tajribasi kerak bo'lsa, edit() ni JSX bilan alohida chizib (frontend render.php bilan farqlanishi mumkin), ServerSideRender o'rniga @wordpress/data (23-bob) bilan ma'lumotni JS'da olasiz. Ko'p hollarda ServerSideRender yetarli.
β οΈ ServerSideRender β alohida paket. U @wordpress/block-editor ichida emas, balki @wordpress/server-side-render paketida. Import qatorini to'g'ri yozing; npm install @wordpress/server-side-render kerak bo'lishi mumkin (build bog'liqlik sifatida aniqlaydi).
To'liq namuna: "So'nggi kitoblar" dynamic bloki¶
Endi hammasini birlashtiramiz. Izchil namuna plugin'imiz kitoblar-katalogi ga dynamic blok qo'shamiz: kitob CPT'sidan eng so'nggi N ta kitobni (ixtiyoriy janr taksonomiyasi bo'yicha) ro'yxatga oladi.
block.json¶
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "oqil/songgi-kitoblar",
"version": "0.1.0",
"title": "So'nggi kitoblar",
"category": "widgets",
"icon": "book-alt",
"description": "Eng so'nggi qo'shilgan kitoblarni ko'rsatuvchi dynamic blok.",
"attributes": {
"janr": { "type": "string", "default": "" },
"soni": { "type": "number", "default": 5 }
},
"supports": {
"html": false
},
"textdomain": "kitoblar-katalogi",
"editorScript": "file:./index.js",
"editorStyle": "file:./index.css",
"style": "file:./style-index.css",
"render": "file:./render.php"
}
π janr va soni β sozlama atributlari, sourcesiz (20-bob): ular HTML'da emas, blok izohida JSON sifatida saqlanadi va render.php ga $attributes orqali yetib boradi.
render.php¶
<?php
/**
* Dynamic blok server-render fayli.
*
* Mavjud o'zgaruvchilar:
* $attributes (array): blok atributlari.
* $content (string): blok ichki kontenti.
* $block (WP_Block): blok instansiyasi.
*/
$soni = isset( $attributes['soni'] ) ? absint( $attributes['soni'] ) : 5;
$janr = isset( $attributes['janr'] ) ? sanitize_title( $attributes['janr'] ) : '';
$args = array(
'post_type' => 'kitob',
'posts_per_page' => $soni,
'post_status' => 'publish',
'orderby' => 'date',
'order' => 'DESC',
);
if ( '' !== $janr ) {
$args['tax_query'] = array(
array(
'taxonomy' => 'janr',
'field' => 'slug',
'terms' => $janr,
),
);
}
$soulgi = new WP_Query( $args );
if ( ! $soulgi->have_posts() ) {
echo '<p ' . get_block_wrapper_attributes() . '>'
. esc_html__( 'Hozircha kitob yo\'q.', 'kitoblar-katalogi' )
. '</p>';
return;
}
?>
<div <?php echo get_block_wrapper_attributes(); ?>>
<ul class="kitkat-songgi">
<?php while ( $soulgi->have_posts() ) : $soulgi->the_post(); ?>
<li class="kitkat-songgi__item">
<a href="<?php echo esc_url( get_permalink() ); ?>">
<?php echo esc_html( get_the_title() ); ?>
</a>
</li>
<?php endwhile; ?>
</ul>
</div>
<?php
wp_reset_postdata();
Diqqat qiling:
absint()vasanitize_title()β$attributesdan kelgan qiymatlarni tozalaydi (sonimusbat butun son,janrslug shakliga).WP_Query(query_posts()EMAS β 10-bobdagi qoida) bilankitobCPT'dan tortamiz;tax_querybilanjanrfiltri ixtiyoriy.get_permalink()/get_the_title()natijasiniesc_url()/esc_html()bilan escape qilamiz.wp_reset_postdata()β global$postni tiklaydi (customWP_Querydan keyin SHART, aks holda sahifaning qolgan qismi buziladi).
β οΈ wp_reset_postdata() ni unutmang. the_post() global $post ni o'zgartiradi. Tiklamasangiz, blokdan keyingi kontent (boshqa bloklar, izohlar) noto'g'ri postni ko'rsatadi.
edit.js (yuqorida) va index.js¶
edit.js β yuqoridagi ServerSideRender li komponent. index.js faqat edit registratsiya qiladi (save yo'q):
import { registerBlockType } from '@wordpress/blocks';
import './style.scss';
import Edit from './edit';
import metadata from './block.json';
registerBlockType( metadata.name, { edit: Edit } );
PHP tomoni: ro'yxatdan o'tkazish¶
namespace Oqil\KitobKatalog;
add_action( 'init', __NAMESPACE__ . '\\register_kitkat_dynamic_bloklar' );
function register_kitkat_dynamic_bloklar(): void {
register_block_type( __DIR__ . '/build/songgi-kitoblar' );
}
βΉοΈ register_block_type( string|WP_Block_Type $block_type, array $args = array() ): WP_Block_Type|false β birinchi argument block.json joylashgan papka yo'li bo'lishi mumkin (developer.wordpress.org bilan tasdiqlangan). block.json dagi "render" avtomatik o'qiladi β bu yerda render_callback berish shart emas.
βΉοΈ O'z saytingizda sinab ko'ring. Bu kod sintaktik to'g'ri (php -l dan o'tdi) va blok npm run build bilan haqiqatan qurildi, lekin natijani ko'rish uchun kitob CPT'da nechta nashr etilgan post va ishlab turgan WordPress sayt kerak (02-bobdagi wp-env). Plugin'ni aktivatsiya qiling, bir nechta kitob qo'shing, postga "So'nggi kitoblar" blokini joylashtiring β muharrirda ServerSideRender ro'yxatni ko'rsatadi, frontendda har so'rovda yangilanadi.
PHP-only blok registratsiya (JS build'siz)¶
Yuqoridagi blok ServerSideRender (edit.js) ishlatadi, demak JS build kerak. Lekin ko'p sodda server bloklarida muharrir tajribasi murakkab emas β shunchaki render natijasini ko'rsatish kifoya. Bunday hollarda 2026 da JS build umuman shart emas: faqat block.json + render.php bilan blok yaratasiz.
Siri shunda: block.json dagi editorScript ixtiyoriy. Agar uni bermasangiz va "render": "file:./render.php" bersangiz, blok JS'siz ro'yxatdan o'tadi. Muharrirda WordPress (yetarlicha yangi versiyalarda) render.php natijasini o'zi server orqali ko'rsatadi.
Fayl tuzilishi (faqat ikki fayl)¶
block.json (JS yo'q)¶
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "oqil/eslatma",
"title": "Eslatma qutisi",
"category": "widgets",
"icon": "info",
"textdomain": "kitoblar-katalogi",
"render": "file:./render.php"
}
π editorScript, index.js, edit.js, save.js β birortasi ham yo'q. Webpack ham, npm run build ham kerak emas. block.json + render.php β vassalom.
render.php¶
<?php
/**
* PHP-only blok: faqat block.json + shu fayl.
*/
?>
<div <?php echo get_block_wrapper_attributes(); ?>>
<p><?php esc_html_e( 'Bu kitob tahririyat tavsiyasi.', 'kitoblar-katalogi' ); ?></p>
</div>
Ro'yxatdan o'tkazish (build papkasiz)¶
namespace Oqil\KitobKatalog;
add_action( 'init', __NAMESPACE__ . '\\register_php_only_blok' );
function register_php_only_blok(): void {
register_block_type( __DIR__ . '/bloklar/eslatma' );
}
βΉοΈ Bu yo'l empirik tasdiqlangan: @wordpress/create-block <nom> --variant dynamic --no-plugin aynan shunday strukturani (block.json + render.php, package.json/build YO'Q) yaratadi. register_block_type papkadan block.json ni o'qiydi, "render" render.php ga ishora qiladi β JS qadami umuman bo'lmaydi.
π Qachon PHP-only mos? Muharrirda murakkab tahrirlash kerak bo'lmaganda: statik eslatma/banner, "so'nggi N ta post" kabi sozlamasiz yoki minimal sozlamali ro'yxat, qisqa server-render fragment. PHP biluvchi, lekin React/build ishtiyoqi yo'q dasturchi uchun ideal kirish nuqtasi.
β οΈ Cheklov. PHP-only blokda boy muharrir UI (RichText, sudralib o'zgaradigan InspectorControls) yo'q β atributlarni boshqarish uchun baribir JS (edit.js) kerak bo'ladi. Atributli, muharrirda sozlanadigan blok kerak bo'lsa β yuqoridagi ServerSideRender li to'liq variant. PHP-only β eng sodda holatlar uchun.
Build qilish va tekshirish¶
ServerSideRender li variant JSX ishlatadi, shuning uchun @wordpress/scripts bilan quriladi:
π‘ Bu bobning kodi haqiqatan tekshirilgan. Dynamic blok @wordpress/create-block@latest songgi-kitoblar --namespace oqil --variant dynamic bilan scaffold qilindi (u render.php ni avtomatik yaratadi β $attributes/$content/$block izohi bilan). Yuqoridagi edit.js (ServerSideRender bilan), render.php (WP_Query) va block.json joylanib, @wordpress/server-side-render o'rnatilgach npm run build ishga tushirildi β webpack compiled successfully qaytardi. build/songgi-kitoblar/index.asset.php ichida bog'liqliklar paydo bo'ldi: wp-block-editor, wp-blocks, wp-components, wp-i18n va wp-server-side-render (bu β ServerSideRender importi to'g'riligining ishonchli tasdig'i; JSX'ni node --check topa olmaydi). render.php build/ ga nusxalandi va php -l dan xatosiz o'tdi.
Xulosa¶
- Dynamic blok HTML ni
post_contentga muzlatmaydi β har so'rovdarender.php(yokirender_callback) qaytadan hisoblaydi. O'zgaruvchan/tashqi ma'lumot uchun. - Static vs dynamic: ma'lumot o'zgarmasa β static (tez); o'zgarsa β dynamic. Dynamicda "block validation" muammosi yo'q (
savenull). - Ikki registratsiya yo'li:
block.json"render": "file:./render.php"(afzal, deklarativ) yokiregister_block_type(..., ['render_callback' => ...]).render.phpecho qiladi,render_callbackreturn qiladi. render.phpo'zgaruvchilari:$attributes(array),$content(string),$block(WP_Block) β avtomatik ochiq.get_block_wrapper_attributes()β eng tashqi elementga (PHP'dagiuseBlockProps.save()ekvivalenti); natija allaqachon escape qilingan.- Escape SHART:
render.phpJSX emas βesc_html/esc_attr/esc_urlbilan har chiqishni escape qiling.WP_Querydan keyinwp_reset_postdata(). ServerSideRender(@wordpress/server-side-render) β muharrirdarender.phpnatijasini ko'rsatadi.- PHP-only blok (2026): faqat
block.json(editorScriptsiz) +render.php, JS build'siz β sodda server bloklar uchun.
Keyingi bobda blokni kengaytiramiz: variations (bir blokning bir nechta tayyor varianti), styles (uslublar), InnerBlocks (blok ichida blok) va patterns (blok andozalari).
21-bob mashqlari¶
Mashqlar
kitoblar-katalogiplugini ustida ishlaydi (nomoqil/songgi-kitoblar, namespaceOqil\KitobKatalog). Dynamic blokni@wordpress/create-block ... --variant dynamicbilan scaffold qiling,render.phpniphp -lbilan, butun blokninpm run buildbilan tekshiring; natijanikitobCPT'liwp-envsaytingizda sinang.
Oson¶
- (Oson) Static va dynamic blok orasidagi tub farqni bir jumlada ayting: HTML qayerda va qachon hisoblanadi?
- (Oson) Dynamic blokda
save()nima qaytaradi? Negaindex.jsdasavebermasangiz ham bo'ladi? - (Oson)
render.phpga avtomatik ochiladigan uchta o'zgaruvchini va ularning tipini ayting. - (Oson)
render.phpda eng tashqi elementga qaysi funksiyani qo'shasiz va u nima qaytaradi? Bu static blokdagi qaysi narsaning ekvivalenti? - (Oson) "So'nggi 5 kitob" ro'yxati uchun static yoki dynamic blok kerak? Nega?
- (Oson)
ServerSideRenderqaysi paketdan import qilinadi va u muharrirda nima qiladi?
O'rta¶
- (O'rta)
block.jsonga"render": "file:./render.php"qo'shing varender.phpdaget_block_wrapper_attributes()bilan o'ralgan oddiy "Salom" matnini chiqaring (escape bilan).
Yechim
block.json (qisman):
render.php:
<div <?php echo get_block_wrapper_attributes(); ?>>
<?php esc_html_e( 'Salom, dynamic blok!', 'kitoblar-katalogi' ); ?>
</div>
get_block_wrapper_attributes() allaqachon escape qilingan atribut stringini qaytaradi (qaytadan escape kerak emas), matnni esa esc_html_e() bilan tarjima qilib escape qilamiz.
- (O'rta)
render.phpda$attributes['soni'](raqam) va$attributes['janr'](slug) ni xavfsiz o'qing. Qaysi sanitize funksiyalarini ishlatasiz va nega?
Yechim
$soni = isset( $attributes['soni'] ) ? absint( $attributes['soni'] ) : 5;
$janr = isset( $attributes['janr'] ) ? sanitize_title( $attributes['janr'] ) : '';
absint() β manfiy yoki kasr sonlardan himoya, musbat butun son beradi (posts_per_page uchun). sanitize_title() β qiymatni slug shakliga keltiradi (taksonomiya slug solishtiruvi uchun). $attributes foydalanuvchidan keladi, shuning uchun ishonib bo'lmaydi.
- (O'rta)
render_callbackvablock.json"render"orasidagi farqni ayting: qaysi biriecho, qaysi birireturnqiladi? Qaysi vaziyatdarender_callbackqulayroq?
Yechim
block.json"render": "file:./render.php"βrender.phpto'g'ridan-to'g'ri output echo qiladi (?>...<?phpyokiecho).render_callbackβregister_block_typega berilgan PHP funksiya; u HTML stringni return qiladi (echo qilsa, blok o'rni buziladi).
render_callback qulayroq: render mantig'i sinf metodi/dinamik aniqlanadigan callback bo'lsa, bir blokni turli render bilan bir necha bor ro'yxatdan o'tkazsangiz, yoki block.json'siz eski uslubda. Yangi loyihada deklarativ "render" afzal.
- (O'rta) Quyidagi
render.phpxato beradi. Sababini toping va to'g'rilang:
Yechim
Uch muammo:
get_block_wrapper_attributes()yo'q β wrapper elementi yo'q,supports/class markupga tushmaydi.- Escape yo'q β
get_the_title()sarlavhasida HTML bo'lishi mumkin (XSS).esc_html()kerak. wp_reset_postdata()yo'q β global$posttiklanmaydi, sahifaning qolgani buziladi.
To'g'risi:
- (O'rta)
edit.jsdaServerSideRendergablockvaattributesprops'larini bering.attributeso'zgarganda nima sodir bo'ladi?
Yechim
import ServerSideRender from '@wordpress/server-side-render';
// ...
<ServerSideRender
block="oqil/songgi-kitoblar"
attributes={ attributes }
/>
attributes o'zgarganda (masalan foydalanuvchi soni ni yangilasa) ServerSideRender render.php ni REST orqali qayta chaqiradi va muharrirda yangi natijani ko'rsatadi. Shuning uchun muharrir ko'rinishi frontend bilan bir xil bo'ladi.
- (O'rta) Dynamic blokda nega "block validation" xatosi umuman bo'lmaydi? Buni static blok bilan solishtiring.
Yechim
"Block validation" xatosi WordPress saqlangan HTML'ni joriy save() chiqargani bilan taqqoslaganda mos kelmasa yuzaga keladi (static blok). Dynamic blokda save() null qaytaradi β post_content ga muzlatilgan markup yo'q, demak taqqoslanadigan narsa yo'q. HTML har so'rovda render.php da yangi hosil bo'ladi, shuning uchun markupni o'zgartirish (faqat render.php ni tahrirlash) eski postlarni buzmaydi. Static blokda esa save() o'zgarishi deprecated/migratsiya talab qiladi.
Qiyin¶
- (Qiyin) To'liq "So'nggi kitoblar" dynamic blokini yozing:
block.json(janr,soniatributlari,"render"),render.php(WP_QuerykitobCPT, ixtiyoriyjanrtax_query, escape,wp_reset_postdata),edit.js(ServerSideRender+ InspectorControls),index.js(savesiz).
Yechim
block.json:
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "oqil/songgi-kitoblar",
"title": "So'nggi kitoblar",
"category": "widgets",
"icon": "book-alt",
"textdomain": "kitoblar-katalogi",
"attributes": {
"janr": { "type": "string", "default": "" },
"soni": { "type": "number", "default": 5 }
},
"supports": { "html": false },
"editorScript": "file:./index.js",
"render": "file:./render.php"
}
render.php:
<?php
$soni = isset( $attributes['soni'] ) ? absint( $attributes['soni'] ) : 5;
$janr = isset( $attributes['janr'] ) ? sanitize_title( $attributes['janr'] ) : '';
$args = array(
'post_type' => 'kitob',
'posts_per_page' => $soni,
'post_status' => 'publish',
);
if ( '' !== $janr ) {
$args['tax_query'] = array(
array( 'taxonomy' => 'janr', 'field' => 'slug', 'terms' => $janr ),
);
}
$q = new WP_Query( $args );
if ( ! $q->have_posts() ) {
echo '<p ' . get_block_wrapper_attributes() . '>'
. esc_html__( 'Kitob yo\'q.', 'kitoblar-katalogi' ) . '</p>';
return;
}
?>
<ul <?php echo get_block_wrapper_attributes(); ?>>
<?php while ( $q->have_posts() ) : $q->the_post(); ?>
<li><a href="<?php echo esc_url( get_permalink() ); ?>"><?php echo esc_html( get_the_title() ); ?></a></li>
<?php endwhile; ?>
</ul>
<?php wp_reset_postdata();
edit.js:
import { __ } from '@wordpress/i18n';
import { useBlockProps, InspectorControls } from '@wordpress/block-editor';
import { PanelBody, TextControl, RangeControl } from '@wordpress/components';
import ServerSideRender from '@wordpress/server-side-render';
export default function Edit( { attributes, setAttributes } ) {
const { janr, soni } = attributes;
return (
<>
<InspectorControls>
<PanelBody title={ __( 'Sozlamalar', 'kitoblar-katalogi' ) }>
<TextControl label={ __( 'Janr slug', 'kitoblar-katalogi' ) }
value={ janr } onChange={ ( v ) => setAttributes( { janr: v } ) } />
<RangeControl label={ __( 'Nechta', 'kitoblar-katalogi' ) }
value={ soni } onChange={ ( v ) => setAttributes( { soni: v } ) }
min={ 1 } max={ 10 } />
</PanelBody>
</InspectorControls>
<div { ...useBlockProps() }>
<ServerSideRender block="oqil/songgi-kitoblar" attributes={ attributes } />
</div>
</>
);
}
index.js:
import { registerBlockType } from '@wordpress/blocks';
import Edit from './edit';
import metadata from './block.json';
registerBlockType( metadata.name, { edit: Edit } );
npm install @wordpress/server-side-render so'ng npm run build bilan tekshiring β index.asset.php da wp-server-side-render bo'lishi kerak.
- (Qiyin) PHP-only blok yozing: faqat
block.json(editorScriptsiz,"render"bilan) +render.php, hech qanday JS build'siz.register_block_typebilan ro'yxatdan o'tkazing. Bu yondashuv qachon mos, qachon mos emas?
Yechim
bloklar/eslatma/block.json:
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "oqil/eslatma",
"title": "Eslatma qutisi",
"category": "widgets",
"icon": "info",
"textdomain": "kitoblar-katalogi",
"render": "file:./render.php"
}
bloklar/eslatma/render.php:
<div <?php echo get_block_wrapper_attributes(); ?>>
<p><?php esc_html_e( 'Tahririyat tavsiyasi.', 'kitoblar-katalogi' ); ?></p>
</div>
Ro'yxatdan o'tkazish:
editorScript yo'q, demak index.js/edit.js/webpack ham yo'q β npm run build kerak emas. Mos: sodda server-render bloklar (banner, eslatma, sozlamasiz/minimal sozlamali ro'yxat), PHP biluvchi build'siz dasturchi. Mos emas: boy muharrir UI (RichText, sudralib o'zgaradigan sozlamalar) kerak bo'lsa β atributlarni boshqarish uchun baribir edit.js (JS) kerak.
- (Qiyin)
render_callbackversiyasini yozing:register_block_typegarender_callbackbering, callbackarray $attributes, string $content, \WP_Block $blockqabul qilsin va HTML string return qilsin (echo emas). Negarender.phpecho, lekinrender_callbackreturnqiladi?
Yechim
namespace Oqil\KitobKatalog;
add_action( 'init', __NAMESPACE__ . '\\register_callback_blok' );
function register_callback_blok(): void {
register_block_type(
__DIR__ . '/build/songgi-kitoblar',
array( 'render_callback' => __NAMESPACE__ . '\\render_songgi' )
);
}
function render_songgi( array $attributes, string $content, \WP_Block $block ): string {
$soni = absint( $attributes['soni'] ?? 5 );
$q = new \WP_Query( array(
'post_type' => 'kitob', 'posts_per_page' => $soni, 'post_status' => 'publish',
) );
if ( ! $q->have_posts() ) {
return '<p ' . get_block_wrapper_attributes() . '>'
. esc_html__( 'Kitob yo\'q.', 'kitoblar-katalogi' ) . '</p>';
}
$html = '<ul ' . get_block_wrapper_attributes() . '>';
while ( $q->have_posts() ) {
$q->the_post();
$html .= '<li><a href="' . esc_url( get_permalink() ) . '">'
. esc_html( get_the_title() ) . '</a></li>';
}
$html .= '</ul>';
wp_reset_postdata();
return $html;
}
render.php WordPress tomonidan output buffer ichida include qilinadi β chiqargan hamma narsa (echo) blok HTML'i bo'ladi. render_callback esa oddiy funksiya: WordPress uning qaytargan qiymatini (return) blok HTML'i sifatida oladi. Callback echo qilsa, output noto'g'ri joyda (boshqa bloklardan oldin) chiqadi.
- (Qiyin) Bir blokni dynamic qilish kerakmi yoki static qoldirish β qaror daraxti tuzing. Kamida 4 mezon (ma'lumot o'zgaruvchanligi, server yuki, validation xatari, muharrir tajribasi) bo'yicha tahlil qiling va har biriga misol bering.
Yechim
- Ma'lumot o'zgaruvchanligimi? O'zgarsa (so'nggi postlar, narx, hisoblagich) β dynamic; o'zgarmasa (iqtibos, kitob kartasi) β static.
- Server yuki. Static β frontda PHP hisoblamaydi (tez, keshlanadi). Dynamic β har so'rovda
render.php+WP_Query. Yuqori trafikli "o'zgarmas" blokni dynamic qilish β keraksiz yuk; static afzal. - Validation xatari. Static
save()"muzlatilgan kontrakt" β markup o'zgarishi eski postlarni buzadi (deprecated/migratsiya kerak). Dynamicsave() = nullβ bu xatar yo'q, markupnirender.phpda bemalol o'zgartirasiz. - Muharrir tajribasi. Murakkab tahrirlash (RichText, inline tahrir) kerak bo'lsa β static
edit()/save()qulay; dynamic'daServerSideRenderfaqat natijani ko'rsatadi (tahrir yo'q).
Qaror: ma'lumot o'zgarsa β dynamic. O'zgarmasa, lekin markup tez-tez yangilanadi yoki migratsiyadan qochmoqchi bo'lsangiz β dynamic ham mantiqiy. O'zgarmas + yuqori trafik + boy muharrir tahriri β static. Aralash (qisman o'zgaruvchan) β 22-23-boblardagi InnerBlocks yoki @wordpress/data bilan gibrid.
- (Qiyin) Quyidagi dynamic blok muharrirda bo'sh ko'rinadi (frontendda ishlaydi). Sababini toping.
edit.js:
Yechim
Muammo: edit() muharrirda hech narsa render qilmaydi β bo'sh <div>. Dynamic blokda "haqiqiy" HTML faqat serverda (render.php) hosil bo'ladi; muharrir uni avtomatik chaqirmaydi. Natijada muharrirda blok bo'sh ko'rinadi (garchi frontendda render.php ishlasa ham).
Yechim β muharrirda render natijasini ko'rsatish uchun ServerSideRender:
import { useBlockProps } from '@wordpress/block-editor';
import ServerSideRender from '@wordpress/server-side-render';
export default function Edit( { attributes } ) {
return (
<div { ...useBlockProps() }>
<ServerSideRender block="oqil/songgi-kitoblar" attributes={ attributes } />
</div>
);
}
Endi muharrir render.php ni REST orqali chaqirib, frontenddagi bilan bir xil ko'rinishni ko'rsatadi. (Yoki PHP-only blok bo'lsa β editorScript umuman bermay, WordPress render natijasini o'zi ko'rsatadi.)
β¬ οΈ Oldingi: 20 β Static blok: edit, save, attributes Β· π README Β· Keyingi: 22 β Blok variations, styles, InnerBlocks, patterns β‘οΈ