20 β Static blok: edit, save, attributes¶
β¬ οΈ Oldingi: 19 β Blok muharririga kirish va create-block Β· π README Β· Keyingi: 21 β Dynamic blok va PHP-only registratsiya β‘οΈ
Bu bobda: static (statik) blokni 0 dan to'liq quramiz β
edit()funksiyasi muharrirdagi tahrirlanadigan ko'rinishni JSX bilan chizadi,save()esapost_contentga yoziladigan HTML markupini qaytaradi (DB da matn sifatida saqlanadi, dynamic blokdan farqi shu);useBlockProps()vauseBlockProps.save()majburiy wrapper props'ini,@wordpress/element/@wordpress/components/@wordpress/block-editorpaketlarini,block.jsondagiattributes(type,sourcehtml/text/attribute/query,selector,default) vaattributes/setAttributesmexanikasini,RichText(muharrirda) vaRichText.Content(save'da) ni,InspectorControls+PanelBody+TextControl/ToggleControl/ColorPaletteyon panelini, hamdasupports(color/spacing/typography/align) orqali yadro UI'ni avtomatik olishni o'rganamiz β natijada izchil namuna plugin'imizga "Kitob kartasi" static blokini qo'shamiz.
Muammo: kontentga "tayyor qadoq" kerak¶
19-bobda blok muharriri arxitekturasini ko'rdik, @wordpress/create-block bilan blok scaffold qildik va uni register_block_type bilan ro'yxatdan o'tkazdik. Lekin o'sha blok faqat "salom dunyo" matnini ko'rsatardi. Endi haqiqiy ish: foydalanuvchi o'zi to'ldiradigan blok kerak.
Tasavvur qiling β bloggerimiz har postda kitob tavsiya qiladi: sarlavha, muallif, qisqa tavsif, rangli karta. Buni har safar HTML bilan qo'lda yozish β azob. Buning o'rniga "Kitob kartasi" blokini beramiz: foydalanuvchi blokni qo'shadi, maydonlarni to'ldiradi, rangni tanlaydi β tayyor.
Eng muhim qaror: bu static blok bo'ladimi yoki dynamic? Farqi β ma'lumot qayerda yashashida:
- Static blok (bu bob):
save()funksiyasi tayyor HTML ni qaytaradi, WordPress unipost_contentga matn sifatida yozadi. Sahifa ko'rsatilganda PHP hech narsa hisoblamaydi β HTML allaqachon DB da. Tez, sodda, mustaqil. - Dynamic blok (21-bob):
save()nullqaytaradi (yoki minimal), HTML har so'rovda PHP (render.php) tomonidan qayta hisoblanadi. "Eng so'nggi 5 ta kitob" kabi o'zgaruvchan ma'lumot uchun.
π Qachon static? Ma'lumot bir marta kiritiladi va o'zgarmaydi (kitob kartasi, ogohlantirish qutisi, iqtibos). Ma'lumot vaqt o'tishi bilan yoki boshqa joydan o'zgarsa β dynamic. Kitob kartamiz static: bir marta to'ldirilgan kitob ma'lumoti o'zgarmaydi.
edit va save: blokning ikki yuzi¶
Har bir blok registerBlockType ga ikkita funksiya beradi (19-bobdan index.js ni eslang):
registerBlockType( metadata.name, {
edit: Edit, // muharrirda nima ko'rinadi (tahrirlanadi)
save, // post_content ga nima yoziladi (HTML)
} );
editβ React komponent. Muharrirda blok tanlanganda WordPress shuni render qiladi. Foydalanuvchi shu yerda tahrir qiladi.saveβ sof funksiya. Foydalanuvchi postni saqlaganda WordPresssave()ni chaqirib, qaytgan JSX ni HTML stringga aylantiradi vapost_contentga yozadi.
β οΈ save "jonli" emas. save() muharrirda yoki frontendda ishlamaydi β u faqat saqlash payti markupni bir marta ishlab chiqaradi. Shuning uchun save() ichida hodisa (onClick), holat (useState) yoki effekt bo'lmaydi: u faqat statik HTML qaytaradi. Interaktivlik kerak bo'lsa β frontend uchun alohida viewScript (view.js) yoki dynamic blok.
React global emas β import qiling¶
β οΈ Blok muharririda React global o'zgaruvchi sifatida mavjud emas. Hamma narsa @wordpress/* paketlaridan import qilinadi va @wordpress/scripts (webpack) ularni wp.element, wp.blockEditor kabi global'larga ulaydi. JSX'ni React o'rniga @wordpress/element quvvatlaydi (u React'ning yupqa o'ramasi). Asosiy paketlar:
| Paket | Nima beradi |
|---|---|
@wordpress/element |
React abstraktsiyasi (useState, Fragment, JSX runtime) |
@wordpress/block-editor |
useBlockProps, RichText, InspectorControls, BlockControls |
@wordpress/components |
UI: PanelBody, TextControl, ToggleControl, ColorPalette |
@wordpress/i18n |
__() β JS tarjimasi |
@wordpress/blocks |
registerBlockType |
βΉοΈ @wordpress/scripts import qilingan har bir @wordpress/* paketni avtomatik aniqlaydi va build/<blok>/index.asset.php fayliga bog'liqliklarni yozadi (masalan wp-block-editor, wp-components, wp-i18n). WordPress shu fayl asosida kerakli skriptlarni yuklaydi β siz qo'lda enqueue qilmaysiz.
useBlockProps: majburiy wrapper¶
Blokning eng tashqi elementiga useBlockProps() dan kelgan props'ni tarqatish majburiy. U WordPress kutadigan class, id, tekislash (align), rang, bo'shliq kabi atributlarni qo'shadi. Busiz blok tanlanmaydi, supports ishlamaydi va muharrir ogohlantirish beradi.
import { useBlockProps } from '@wordpress/block-editor';
export default function Edit() {
const blockProps = useBlockProps(); // muharrirda
return <div { ...blockProps }>Salom</div>;
}
save() da esa useBlockProps.save() (statik variant β hook emas, lekin shu nom bilan):
export default function save() {
const blockProps = useBlockProps.save(); // saqlanadigan markupda
return <div { ...blockProps }>Salom</div>;
}
π useBlockProps() muharrirda, useBlockProps.save() save'da. Ikkalasiga ham xohlasangiz qo'shimcha props berasiz: useBlockProps( { className: 'kitkat-karta', style: {...} } ). Bu sizning class'ingizni yadro class'lari bilan birlashtiradi (ustiga yozmaydi).
β οΈ useBlockProps ni faqat eng tashqi (root) elementga bering β ichki elementlarga emas. Har blokda bitta root element bo'ladi.
Attributes: blok ma'lumotini saqlash¶
Blok foydalanuvchi kiritgan ma'lumotni qayerda saqlaydi? attributes da. block.json ning attributes bo'limi har bir maydonni e'lon qiladi: tipi, qiymat qayerdan o'qilishi va sukut (default) qiymati.
"attributes": {
"sarlavha": {
"type": "string",
"source": "html",
"selector": ".kitkat-karta__sarlavha",
"default": ""
},
"muallif": {
"type": "string",
"default": ""
},
"chegaraKorinsin": {
"type": "boolean",
"default": true
},
"fonRangi": {
"type": "string",
"default": "#dbeafe"
}
}
Har bir attribute'ning kalitlari:
typeβ"string","number","integer","boolean","array","object"(JSON Schema tiplari).sourceβ qiymat qayerdan o'qiladi (sahifa qayta yuklanganda):"html"βselectortopgan element ichidagi HTML (formatlangan matn)."text"βselectorichidagi sof matn (teglarsiz)."attribute"β element atributining qiymati (attribute: "href")."query"β bir nechta elementdan massiv (masalan ro'yxat).sourceyo'q (eng oddiy) β qiymat markup'dan o'qilmaydi; u blok izohida (HTML comment) JSON sifatida saqlanadi.selectorβsourcebilan ishlatiladigan CSS selektor (qaysi elementdan o'qish).defaultβ boshlang'ich qiymat.
source bilan va sourcesiz: ikki saqlash usuli¶
Bu β eng chalkash, lekin eng muhim tushuncha. Static blokda attribute qiymati ikki joydan birida yashashi mumkin:
-
sourcebilan (markup ichida). Qiymatsave()chizgan HTML ichida yashaydi. Qayta yuklanganda WordPressselector+sourcebo'yicha uni markup'dan qayta o'qiydi.RichTextbilan ishlatiladigansarlavha/tavsifshunday. -
sourcesiz (blok izohida). Qiymat HTML'da ko'rinmaydi; u blok izohida JSON sifatida saqlanadi:<!-- wp:oqil/kitob-kartasi {"muallif":"Oqil","fonRangi":"#dbeafe"} --> <div class="wp-block-oqil-kitob-kartasi kitkat-karta">...</div> <!-- /wp:oqil/kitob-kartasi -->muallif,chegaraKorinsin,fonRangishunday β ular HTML'ga matn sifatida chiqmasligi mumkin, lekin blokda saqlanadi.
π Qoida: tahrirlanadigan matn (RichText) odatda source: "html" bilan markup'dan o'qiladi (toza, qidiriladi, boshqa muharrirlar ham ko'radi). Sozlama qiymatlari (rang, toggle, son) odatda sourcesiz β blok izohida. Ikkalasi bitta blokda birga yashashi normal.
attributes va setAttributes edit ichida¶
edit komponent ikkita prop oladi (boshqalari ham bor): attributes (joriy qiymatlar obyekti) va setAttributes (yangilash funksiyasi).
export default function Edit( { attributes, setAttributes } ) {
const { sarlavha, muallif } = attributes;
return (
<input
value={ muallif }
onChange={ ( e ) => setAttributes( { muallif: e.target.value } ) }
/>
);
}
β οΈ attributes ni to'g'ridan-to'g'ri o'zgartirmang (attributes.muallif = '...' β XATO). Faqat setAttributes({ muallif: '...' }). Bu React holat yangilash qoidasi: setAttributes faqat berilgan kalitlarni birlashtiradi (qolganini saqlaydi) va qayta render'ni triggerlaydi.
RichText: tahrirlanadigan matn¶
Oddiy <input> faqat sof matn beradi. Lekin foydalanuvchi sarlavhada qalin (bold) yoki kursiv (italic) ishlatmoqchi bo'lsa-chi? Buning uchun RichText β WordPress'ning tahrirlanadigan, formatlanadigan matn komponenti.
import { RichText } from '@wordpress/block-editor';
// edit() ichida:
<RichText
tagName="h3"
className="kitkat-karta__sarlavha"
value={ sarlavha }
onChange={ ( yangi ) => setAttributes( { sarlavha: yangi } ) }
placeholder={ __( 'Kitob nomiβ¦', 'kitoblar-katalogi' ) }
allowedFormats={ [ 'core/bold', 'core/italic' ] }
/>
tagNameβ qaysi HTML teg chiqishi (h3,p,span...).value/onChangeβattributes.sarlavhabilan bog'lash.placeholderβ bo'sh bo'lsa ko'rinadigan eslatma.allowedFormatsβ ruxsat berilgan formatlash (bo'sh massiv = formatlash yo'q).
save() da esa RichText.Content β formatlangan qiymatni HTML sifatida chiqaradi:
import { RichText } from '@wordpress/block-editor';
// save() ichida:
<RichText.Content
tagName="h3"
className="kitkat-karta__sarlavha"
value={ sarlavha }
/>
π RichText edit'da, RichText.Content save'da. tagName va className ikkalasida bir xil bo'lishi kerak β chunki block.json dagi selector: ".kitkat-karta__sarlavha" aynan shu class'dan qiymatni qayta o'qiydi. Mos kelmasa β qiymat yo'qoladi.
βΉοΈ Bu importlar developer.wordpress.org Block Editor Handbook bilan tasdiqlangan: import { useBlockProps, RichText } from '@wordpress/block-editor'; va save'da <RichText.Content ... value={ attributes.content } />.
edit va save markup MOS kelishi: "block validation"¶
Bu β static blokdagi eng ko'p uchraydigan xato manbai, shuning uchun alohida ta'kidlaymiz.
Sahifa qayta yuklanganda WordPress post_content dagi saqlangan HTML'ni o'qiydi va joriy save() funksiyasini qayta ishga tushirib, ikkalasini taqqoslaydi. Agar ular bir xil bo'lmasa β "block validation" (blok tekshiruvi) xatosi: muharrir "This block contains unexpected or invalid content" deydi va blokni "qutqarish" yoki "tiklash" ni so'raydi.
β οΈ Nega buziladi? Siz save() markupini o'zgartirsangiz (class nomi, teg, tuzilish), eski postlardagi saqlangan HTML yangi save() chiqargani bilan mos kelmaydi. Shuning uchun:
save()ni o'ylab yozing β keyin o'zgartirish eski kontentni buzadi.- Agar
save()ni o'zgartirishingiz shart bo'lsa, deprecation (eskirgan versiya) e'lon qilasiz:block.json/registerBlockTypegadeprecatedmassivini berib, eski markupni ham tushunadigan migratsiya yozasiz. (Bu mavzu β ilg'or; hozircha bilingki,save()"muzlatilgan kontrakt".)
π‘ Maslahat. save() ni iloji boricha sodda saqlang. Murakkab, tez-tez o'zgaradigan ko'rinish kerak bo'lsa β dynamic blok (render.php, 21-bob): u save() ni null qiladi, shuning uchun validation muammosi umuman bo'lmaydi.
InspectorControls: yon panel sozlamalari¶
Matnni blokning o'zida tahrirlaymiz, lekin sozlamalar (rang, toggle, qo'shimcha matn) qayerda? Ularni blok ichiga tiqishtirish chiroyli emas. WordPress buning uchun yon panel (Settings sidebar) beradi β InspectorControls.
InspectorControls ichiga qo'ygan hamma narsa muharrirning o'ng tomonidagi sozlamalar panelida (blok tanlanganda) ko'rinadi:
import { InspectorControls } from '@wordpress/block-editor';
import { PanelBody, TextControl, ToggleControl, ColorPalette } from '@wordpress/components';
<InspectorControls>
<PanelBody title={ __( 'Karta sozlamalari', 'kitoblar-katalogi' ) }>
<TextControl
label={ __( 'Muallif', 'kitoblar-katalogi' ) }
value={ muallif }
onChange={ ( yangi ) => setAttributes( { muallif: yangi } ) }
/>
<ToggleControl
label={ __( 'Chegara chizig\'i', 'kitoblar-katalogi' ) }
checked={ chegaraKorinsin }
onChange={ ( yoq ) => setAttributes( { chegaraKorinsin: yoq } ) }
/>
<ColorPalette
value={ fonRangi }
onChange={ ( rang ) => setAttributes( { fonRangi: rang } ) }
/>
</PanelBody>
</InspectorControls>
PanelBodyβ yig'iladigan (collapsible) bo'lim,titlebilan.TextControlβ bitta qatorli matn maydoni.ToggleControlβ yoq/o'chiq tugmasi (boolean).ColorPaletteβ rang tanlash (tema palitrasi + maxsus rang).
π‘ BlockControls β toolbar. InspectorControls yon panel uchun bo'lsa, BlockControls blok ustidagi suzuvchi toolbar uchun (tekislash, formatlash tugmalari). Ikkalasi ham @wordpress/block-editor dan keladi. Toolbar β tez-tez ishlatiladigan amallar uchun; yon panel β kamroq ishlatiladigan sozlamalar uchun.
βΉοΈ Bu komponentlar (PanelBody, TextControl, ToggleControl, ColorPalette) β @wordpress/components paketining standart eksportlari. Quyida butun blokni npm run build bilan haqiqatan qurganimizda webpack ularning hammasini muvaffaqiyatli hal qildi (index.asset.php da wp-components bog'liqligi paydo bo'ldi) β bu importlar to'g'riligining tasdig'i.
supports: yadro UI'ni bepul olish¶
block.json ning supports bo'limi β sehrli qisqartma. Unda bir nechta xususiyatni true qilsangiz, WordPress avtomatik ravishda yon panelga mos sozlamalarni qo'shadi va useBlockProps ularni markupga ulaydi β siz hech qanday UI yozmaysiz.
"supports": {
"html": false,
"align": [ "wide", "full" ],
"color": {
"text": true,
"background": false
},
"spacing": {
"padding": true,
"margin": true
},
"typography": {
"fontSize": true,
"lineHeight": true
}
}
html": falseβ foydalanuvchi blokni "HTML sifatida tahrirlash" qila olmaydi (xavfsizroq, tavsiya etiladi).alignβ keng/to'liq tekislash tugmalari (toolbar'da).colorβ matn/fon rangi sozlamalari (biztext: trueqildik, fonni o'zColorPalettebilan boshqaramiz).spacingβ padding/margin sozlamalari.typographyβ shrift o'lchami, qator balandligi.
π supports β "bepul" funksiya. Bir qator JSON yozib, yon panelga to'liq ishlaydigan rang/bo'shliq/shrift sozlamalarini qo'shasiz. O'z attributes va setAttributes yozish shart emas β WordPress hammasini o'zi boshqaradi va saqlaydi. Avval supports ni tekshiring; o'z sozlamangiz faqat supports qoplamaydigan narsa uchun.
To'liq namuna: "Kitob kartasi" static bloki¶
Endi hammasini birlashtiramiz. Izchil namuna plugin'imiz kitoblar-katalogi ga static blok qo'shamiz: nom oqil/kitob-kartasi, sarlavha (RichText), muallif (TextControl), tavsif (RichText), chegara toggle va fon rangi. Bu β bobning yuragi.
block.json¶
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "oqil/kitob-kartasi",
"version": "0.1.0",
"title": "Kitob kartasi",
"category": "widgets",
"icon": "book",
"description": "Kitob sarlavhasi, muallifi va tavsifini ko'rsatuvchi karta bloki.",
"keywords": [ "kitob", "karta", "katalog" ],
"textdomain": "kitoblar-katalogi",
"attributes": {
"sarlavha": {
"type": "string",
"source": "html",
"selector": ".kitkat-karta__sarlavha",
"default": ""
},
"muallif": { "type": "string", "default": "" },
"tavsif": {
"type": "string",
"source": "html",
"selector": ".kitkat-karta__tavsif",
"default": ""
},
"chegaraKorinsin": { "type": "boolean", "default": true },
"fonRangi": { "type": "string", "default": "#dbeafe" }
},
"supports": {
"html": false,
"align": [ "wide", "full" ],
"color": { "text": true, "background": false },
"spacing": { "padding": true, "margin": true },
"typography": { "fontSize": true, "lineHeight": true }
},
"editorScript": "file:./index.js",
"editorStyle": "file:./index.css",
"style": "file:./style-index.css"
}
edit.js¶
import { __ } from '@wordpress/i18n';
import {
useBlockProps,
RichText,
InspectorControls,
} from '@wordpress/block-editor';
import {
PanelBody,
TextControl,
ToggleControl,
ColorPalette,
} from '@wordpress/components';
import './editor.scss';
export default function Edit( { attributes, setAttributes } ) {
const { sarlavha, muallif, tavsif, chegaraKorinsin, fonRangi } = attributes;
const blockProps = useBlockProps( {
className: chegaraKorinsin ? 'kitkat-karta has-chegara' : 'kitkat-karta',
style: { backgroundColor: fonRangi },
} );
return (
<>
<InspectorControls>
<PanelBody title={ __( 'Karta sozlamalari', 'kitoblar-katalogi' ) }>
<TextControl
label={ __( 'Muallif', 'kitoblar-katalogi' ) }
value={ muallif }
onChange={ ( yangi ) => setAttributes( { muallif: yangi } ) }
/>
<ToggleControl
label={ __( 'Chegara chizig\'i', 'kitoblar-katalogi' ) }
checked={ chegaraKorinsin }
onChange={ ( yoq ) => setAttributes( { chegaraKorinsin: yoq } ) }
/>
<p>{ __( 'Fon rangi', 'kitoblar-katalogi' ) }</p>
<ColorPalette
value={ fonRangi }
onChange={ ( rang ) => setAttributes( { fonRangi: rang } ) }
/>
</PanelBody>
</InspectorControls>
<div { ...blockProps }>
<RichText
tagName="h3"
className="kitkat-karta__sarlavha"
value={ sarlavha }
onChange={ ( yangi ) => setAttributes( { sarlavha: yangi } ) }
placeholder={ __( 'Kitob nomiβ¦', 'kitoblar-katalogi' ) }
allowedFormats={ [ 'core/bold', 'core/italic' ] }
/>
{ muallif && (
<p className="kitkat-karta__muallif">
{ __( 'Muallif:', 'kitoblar-katalogi' ) } { muallif }
</p>
) }
<RichText
tagName="p"
className="kitkat-karta__tavsif"
value={ tavsif }
onChange={ ( yangi ) => setAttributes( { tavsif: yangi } ) }
placeholder={ __( 'Qisqa tavsifβ¦', 'kitoblar-katalogi' ) }
/>
</div>
</>
);
}
<>...</> β Fragment (@wordpress/element): InspectorControls (panelga "teleport" bo'ladi) va asosiy <div> ni bitta root'siz qaytarish uchun. InspectorControls markupda ko'rinmaydi β u SlotFill orqali yon panelga chiqadi (23-bobda chuqurroq).
save.js¶
import { useBlockProps, RichText } from '@wordpress/block-editor';
export default function save( { attributes } ) {
const { sarlavha, muallif, tavsif, chegaraKorinsin, fonRangi } = attributes;
const blockProps = useBlockProps.save( {
className: chegaraKorinsin ? 'kitkat-karta has-chegara' : 'kitkat-karta',
style: { backgroundColor: fonRangi },
} );
return (
<div { ...blockProps }>
<RichText.Content
tagName="h3"
className="kitkat-karta__sarlavha"
value={ sarlavha }
/>
{ muallif && (
<p className="kitkat-karta__muallif">Muallif: { muallif }</p>
) }
<RichText.Content
tagName="p"
className="kitkat-karta__tavsif"
value={ tavsif }
/>
</div>
);
}
π Diqqat β edit va save mos: ikkalasida <div> root, ichida h3.kitkat-karta__sarlavha, p.kitkat-karta__muallif, p.kitkat-karta__tavsif. className va tagName aynan bir xil. sarlavha/tavsif source: "html" bo'lgani uchun qayta yuklanganda shu class'lardan o'qiladi. muallif sourcesiz β blok izohidan keladi (shuning uchun save'da { muallif && ... } shartli render ham eski postlarni buzmaydi).
index.js (registratsiya β 19-bobdan)¶
import { registerBlockType } from '@wordpress/blocks';
import './style.scss';
import Edit from './edit';
import save from './save';
import metadata from './block.json';
registerBlockType( metadata.name, { edit: Edit, save } );
PHP tomoni: blokni ro'yxatdan o'tkazish¶
Blok JS qurilgach (build/), uni PHP'da ro'yxatdan o'tkazasiz β register_block_type block.json ni o'qiydi:
namespace Oqil\KitobKatalog;
add_action( 'init', __NAMESPACE__ . '\\register_kitkat_bloklar' );
function register_kitkat_bloklar(): void {
register_block_type( __DIR__ . '/build/kitob-kartasi' );
}
βΉοΈ register_block_type( string|WP_Block_Type $block_type, array $args = [] ) katalog yo'lini qabul qiladi va undagi block.json ni o'qiydi (WP 5.8+, docs bilan tasdiqlangan). editorScript/style bog'liqliklari avtomatik enqueue qilinadi.
βΉοΈ O'z saytingizda sinab ko'ring. Bu kod sintaktik to'g'ri va npm run build bilan haqiqatan qurildi, lekin blok muharrirda qanday ko'rinishi, kartani to'ldirib saqlash, frontendda chiqishi β ishlab turgan WordPress saytini talab qiladi (02-bobdagi wp-env). Plugin'ni aktivatsiya qiling, postga "Kitob kartasi" blokini qo'shing.
Build qilish: npm run build¶
JSX va @wordpress/* importlar brauzer tushunmaydigan kod. Ularni @wordpress/scripts (webpack) transpilatsiya qiladi: npm start (kuzatuv rejimi, dev) yoki npm run build (minimal, ishlab chiqarish).
Natija β build/kitob-kartasi/ ichida: index.js (minimal), index.asset.php (bog'liqliklar va versiya), block.json (nusxa), CSS fayllari. PHP register_block_type( __DIR__ . '/build/kitob-kartasi' ) aynan shu papkani o'qiydi.
π‘ Bu bobning kodi haqiqatan qurilgan. Yuqoridagi block.json + edit.js + save.js @wordpress/create-block bilan scaffold qilingan loyihaga joylanib, npm run build ishga tushirildi β webpack compiled successfully qaytardi, build/kitob-kartasi/index.asset.php ichida wp-block-editor, wp-blocks, wp-components, wp-i18n bog'liqliklari paydo bo'ldi. Bu β barcha importlar to'g'riligining ishonchli tasdig'i (JSX'ni node --check topa olmaydi; build topadi).
Xulosa¶
- Static blok:
save()HTML qaytaradi, WordPress unipost_contentga matn sifatida yozadi. PHP sahifa ko'rsatilganda hisoblamaydi (dynamic'dan farqi β 21-bob). editβ muharrirdagi tahrirlanadigan React komponent;saveβ saqlanadigan statik HTML (hodisa/holat yo'q).useBlockProps()(edit) vauseBlockProps.save()(save) eng tashqi elementga majburiy.attributes(block.json):type,source(html/text/attribute/queryyoki yo'q),selector,default.edit'daattributes/setAttributesbilan ishlanadi (to'g'ridan o'zgartirilmaydi).RichText(edit) vaRichText.Content(save) β tahrirlanadigan formatlangan matn;tagName/className/selectormos bo'lishi shart.- edit va save markup MOS kelishi shart β aks holda "block validation" xatosi.
InspectorControls+PanelBody+TextControl/ToggleControl/ColorPaletteβ yon panel;BlockControlsβ toolbar.supports(color/spacing/typography/align) β yadro UI'ni bepul beradi.
Keyingi bobda dynamic blok: save() o'rniga render.php (server-side render) va hatto PHP-only blok ro'yxatdan o'tkazishni ko'ramiz.
20-bob mashqlari¶
Mashqlar
kitoblar-katalogiplugini ustida ishlaydi (nomoqil/kitob-kartasi, namespaceOqil\KitobKatalog). Blok kodini@wordpress/create-blockbilan scaffold qilib,npm run buildbilan tekshiring; muharrir ko'rinishini o'zwp-envsaytingizda sinang.
Oson¶
- (Oson)
editvasavening vazifasini bir jumladan ayting: qaysi biri muharrirda ko'rinadi, qaysi biripost_contentga yoziladi? - (Oson) Nima uchun
save()ichidaonClickyokiuseStateishlatib bo'lmaydi? - (Oson)
useBlockProps()vauseBlockProps.save()qaysi funksiyada (edit/save) ishlatiladi? Ularni qaysi elementga berasiz? - (Oson)
block.jsonda"muallif": { "type": "string", "default": "" }attribute'idasourceyo'q. Qiymat qayerda saqlanadi? - (Oson)
attributes.muallif = 'Oqil'nima uchun xato? To'g'risi qanday? - (Oson)
RichTextvaRichText.Contentfarqi nima? Qaysi biriedit'da, qaysi birisave'da?
O'rta¶
- (O'rta)
block.jsonganarx(number, source yo'q, default 0) attribute'ini qo'shing vaedit'da uniTextControl(type number) bilan boshqaring.
Yechim
block.json da:
edit.js da (PanelBody ichida):
<TextControl
label={ __( 'Narx (so\'m)', 'kitoblar-katalogi' ) }
type="number"
value={ narx }
onChange={ ( yangi ) => setAttributes( { narx: Number( yangi ) } ) }
/>
TextControl doim string beradi, shuning uchun Number( yangi ) bilan songa aylantiramiz (attribute type: "number" ga mos). narx ni const { ..., narx } = attributes; bilan oling.
- (O'rta)
RichTextorqali tahrirlanadigantavsifmaydoni qo'shing:source: "html", selector.kitkat-karta__tavsif,tagName="p".editvasaveikkalasida yozing.
Yechim
block.json:
"tavsif": {
"type": "string",
"source": "html",
"selector": ".kitkat-karta__tavsif",
"default": ""
}
edit.js (asosiy <div> ichida):
<RichText
tagName="p"
className="kitkat-karta__tavsif"
value={ tavsif }
onChange={ ( yangi ) => setAttributes( { tavsif: yangi } ) }
placeholder={ __( 'Qisqa tavsifβ¦', 'kitoblar-katalogi' ) }
/>
save.js:
className/tagName ikkalasida bir xil β selector shu class'dan qiymatni qayta o'qiydi.
- (O'rta)
supportsgacolor.text,spacing.paddingvaalign: ["wide","full"]qo'shing. Bu foydalanuvchiga qanday qo'shimcha sozlamalar beradi va siz qancha JS yozdingiz?
Yechim
"supports": {
"html": false,
"align": [ "wide", "full" ],
"color": { "text": true },
"spacing": { "padding": true }
}
Bu yon panelga matn rangi va padding sozlamalarini, toolbar'ga keng/to'liq tekislash tugmalarini qo'shadi. Hech qanday JS yozmaysiz β useBlockProps yadro qiymatlarini avtomatik markupga ulaydi va saqlaydi. supports β "bepul" UI.
- (O'rta)
ToggleControlbilanchegaraKorinsin(boolean, default true) sozlamasini qo'shing; yoqilganda blok class'igahas-chegaraqo'shilsin.
Yechim
block.json: "chegaraKorinsin": { "type": "boolean", "default": true }.
edit.js:
const blockProps = useBlockProps( {
className: chegaraKorinsin ? 'kitkat-karta has-chegara' : 'kitkat-karta',
} );
// InspectorControls ichida:
<ToggleControl
label={ __( 'Chegara chizig\'i', 'kitoblar-katalogi' ) }
checked={ chegaraKorinsin }
onChange={ ( yoq ) => setAttributes( { chegaraKorinsin: yoq } ) }
/>
save.js da ham aynan shu className mantig'i (useBlockProps.save({ className: ... })) bo'lishi shart β aks holda markup mos kelmaydi.
- (O'rta) Quyidagi
savexato beradi. Sababini toping va to'g'rilang:
Yechim
Ikki muammo:
useBlockProps.save()ishlatilmagan β root elementga majburiy. Busiz blok class'lari,supportsqiymatlari markupga tushmaydi va validation buziladi.sarlavhasource: "html"(RichText) bo'lsa, uni{ attributes.sarlavha }bilan emas,<RichText.Content value={...} />bilan,selector'ga mostagName/classNamebilan chiqarish kerak.
To'g'risi:
import { useBlockProps, RichText } from '@wordpress/block-editor';
export default function save( { attributes } ) {
const blockProps = useBlockProps.save();
return (
<div { ...blockProps }>
<RichText.Content
tagName="h3"
className="kitkat-karta__sarlavha"
value={ attributes.sarlavha }
/>
</div>
);
}
- (O'rta)
import { ColorPalette } from '@wordpress/components'bilan fon rangi tanlash qo'shing vauseBlockProps'ningstyleorqali qo'llang. Negasave'da ham aynan shustyleni berish kerak?
Yechim
// edit.js
<ColorPalette
value={ fonRangi }
onChange={ ( rang ) => setAttributes( { fonRangi: rang } ) }
/>
// blockProps:
const blockProps = useBlockProps( { style: { backgroundColor: fonRangi } } );
save.js da:
save'da ham bir xil style bo'lishi shart, chunki rang post_content HTML'iga inline style sifatida yozilishi kerak β frontendda CSS qayta hisoblanmaydi. edit va save markup (shu jumladan inline style mantig'i) mos kelmasa β validation xatosi.
Qiyin¶
- (Qiyin) To'liq "Kitob kartasi" static blokini yozing:
sarlavha(RichText, source html),muallif(TextControl, source yo'q),tavsif(RichText, source html),fonRangi(ColorPalette).edit(InspectorControls bilan) vasave(RichText.Content bilan) to'liq, mos markup bilan.
Yechim
edit.js:
import { __ } from '@wordpress/i18n';
import { useBlockProps, RichText, InspectorControls } from '@wordpress/block-editor';
import { PanelBody, TextControl, ColorPalette } from '@wordpress/components';
export default function Edit( { attributes, setAttributes } ) {
const { sarlavha, muallif, tavsif, fonRangi } = attributes;
const blockProps = useBlockProps( {
className: 'kitkat-karta',
style: { backgroundColor: fonRangi },
} );
return (
<>
<InspectorControls>
<PanelBody title={ __( 'Karta sozlamalari', 'kitoblar-katalogi' ) }>
<TextControl
label={ __( 'Muallif', 'kitoblar-katalogi' ) }
value={ muallif }
onChange={ ( v ) => setAttributes( { muallif: v } ) }
/>
<ColorPalette
value={ fonRangi }
onChange={ ( v ) => setAttributes( { fonRangi: v } ) }
/>
</PanelBody>
</InspectorControls>
<div { ...blockProps }>
<RichText tagName="h3" className="kitkat-karta__sarlavha"
value={ sarlavha }
onChange={ ( v ) => setAttributes( { sarlavha: v } ) }
placeholder={ __( 'Kitob nomiβ¦', 'kitoblar-katalogi' ) } />
{ muallif && <p className="kitkat-karta__muallif">Muallif: { muallif }</p> }
<RichText tagName="p" className="kitkat-karta__tavsif"
value={ tavsif }
onChange={ ( v ) => setAttributes( { tavsif: v } ) }
placeholder={ __( 'Qisqa tavsifβ¦', 'kitoblar-katalogi' ) } />
</div>
</>
);
}
save.js:
import { useBlockProps, RichText } from '@wordpress/block-editor';
export default function save( { attributes } ) {
const { sarlavha, muallif, tavsif, fonRangi } = attributes;
const blockProps = useBlockProps.save( {
className: 'kitkat-karta',
style: { backgroundColor: fonRangi },
} );
return (
<div { ...blockProps }>
<RichText.Content tagName="h3" className="kitkat-karta__sarlavha" value={ sarlavha } />
{ muallif && <p className="kitkat-karta__muallif">Muallif: { muallif }</p> }
<RichText.Content tagName="p" className="kitkat-karta__tavsif" value={ tavsif } />
</div>
);
}
block.json da sarlavha/tavsif source: "html" mos selector bilan, muallif/fonRangi sourcesiz. Markup edit/save da bir xil. npm run build bilan tekshiring.
- (Qiyin) "Block validation" xatosi nima, qachon kelib chiqadi va
save()ni o'zgartirishingiz kerak bo'lsa eski postlarni qanday saqlab qolasiz?deprecatedtushunchasini izohlang.
Yechim
- Nima: sahifa yuklanganda WordPress saqlangan HTML'ni o'qib, joriy
save()chiqargani bilan taqqoslaydi. Mos kelmasa β "This block contains unexpected or invalid content" xatosi; foydalanuvchi blokni tiklash/o'chirish'ni so'raydi. - Qachon: siz
save()markupini o'zgartirsangiz (class, teg, tuzilish) β eski postlardagi HTML yangisave()ga mos kelmaydi. - Yechim β
deprecated:registerBlockTypega (yoki alohida faylga)deprecatedmassivini berasiz. Har element eskisaveva (kerak bo'lsa)migrate/attributesni saqlaydi. WordPress yangisavemos kelmasa,deprecatedro'yxatidagi eskisavelarni sinab ko'radi; mos kelganini "ko'chiradi" (yangi formatga migratsiya qiladi) β validation xatosisiz.
Shuning uchun save() β "muzlatilgan kontrakt": uni o'zgartirish migratsiya talab qiladi. Tez-tez o'zgaradigan ko'rinish uchun dynamic blok (render.php) afzal β u save ni null qiladi, validation muammosi umuman bo'lmaydi.
- (Qiyin)
source: "html",source: "text",source: "attribute"vasourcesiz (blok izohi) o'rtasidagi farqni har biriga bittadan misol bilan tushuntiring. Qaysi holatda qaysi birini tanlaysiz?
Yechim
source: "html"βselectorichidagi HTML (formatlangan). Misol:RichTextsarlavha β<h3 class="...__sarlavha">Qalin <strong>matn</strong></h3>β qiymat formatlash bilan o'qiladi. Tahrirlanadigan boy matn uchun.source: "text"βselectorichidagi sof matn (teglarsiz). Misol: oddiy yorliq, formatlash kerak bo'lmaganda.source: "attribute"β element atributi qiymati. Misol:{ "type": "string", "source": "attribute", "selector": "a", "attribute": "href" }β havola URL'ini o'qiydi (rasmsrc,altva h.k.).sourcesiz β qiymat HTML'ga bog'lanmaydi; blok izohida JSON sifatida saqlanadi. Misol:fonRangi,chegaraKorinsin,narxβ markupda matn sifatida ko'rinmaydigan sozlamalar.
Tanlov: tahrirlanadigan/qidiriladigan matn β html/text; element atributi (URL, alt) β attribute; sozlama/metadata β sourcesiz.
- (Qiyin) Bu blok
npm run buildda ishlaydimi? Xatoni toping va to'g'rilang:import { useBlockProps } from '@wordpress/block-editor'; import { TextControl } from '@wordpress/block-editor'; export default function Edit( { attributes, setAttributes } ) { return ( <div { ...useBlockProps() }> <InspectorControls> <TextControl value={ attributes.muallif } /> </InspectorControls> </div> ); }
Yechim
Bir nechta xato:
TextControl@wordpress/block-editordan emas,@wordpress/componentsdan keladi β bu import build'daundefinedberadi (yoki xato).InspectorControlsimport qilinmagan (@wordpress/block-editordan kerak).InspectorControls<div { ...useBlockProps() }>ichida emas, yonida (Fragment ichida) bo'lishi kerak β u yon panelga teleport bo'ladi, asosiy markupga emas.TextControlgaonChange/setAttributesulanmagan β tahrirlanmaydi.
To'g'risi:
import { useBlockProps, InspectorControls } from '@wordpress/block-editor';
import { PanelBody, TextControl } from '@wordpress/components';
export default function Edit( { attributes, setAttributes } ) {
const blockProps = useBlockProps();
return (
<>
<InspectorControls>
<PanelBody title="Sozlamalar">
<TextControl
label="Muallif"
value={ attributes.muallif }
onChange={ ( v ) => setAttributes( { muallif: v } ) }
/>
</PanelBody>
</InspectorControls>
<div { ...blockProps }>{ attributes.muallif }</div>
</>
);
}
npm run build da index.asset.php wp-block-editor va wp-components ni ko'rsatishi kerak β bu importlar to'g'riligini tasdiqlaydi.
- (Qiyin)
BlockControls(toolbar) vaInspectorControls(yon panel) farqini ayting: har biri qaysi UI joyida ko'rinadi, qaysi paketdan keladi, va qaysi turdagi sozlama uchun mosroq? Bittadan amaliy misol bering.
Yechim
InspectorControlsβ muharrirning o'ng yon panelida (Settings sidebar), blok tanlanganda.@wordpress/block-editordan. Kamroq ishlatiladigan, batafsil sozlamalar uchun (rang, son, toggle, qo'shimcha matn). Misol:<InspectorControls><PanelBody title="Sozlamalar"><ColorPalette ... /></PanelBody></InspectorControls>.BlockControlsβ blok ustidagi suzuvchi toolbarda.@wordpress/block-editordan. Tez-tez ishlatiladigan, kontekstli amallar uchun (tekislash, format, tugma). Misol:<BlockControls><AlignmentToolbar value={ align } onChange={ ... } /></BlockControls>.
Tanlov: tez va vizual amal β toolbar (BlockControls); batafsil/kamroq sozlama β yon panel (InspectorControls). Ikkalasi ham edit ichida Fragment bilan beriladi va markupga to'g'ridan chiqmaydi (SlotFill).
β¬ οΈ Oldingi: 19 β Blok muharririga kirish va create-block Β· π README Β· Keyingi: 21 β Dynamic blok va PHP-only registratsiya β‘οΈ