{"id":233859,"date":"2023-02-23T17:59:00","date_gmt":"2023-02-23T14:59:00","guid":{"rendered":"https:\/\/wordpress.mediadoma.com\/?p=233859"},"modified":"2023-02-23T18:00:57","modified_gmt":"2023-02-23T15:00:57","slug":"samouczek-utworz-suwak-jako-dynamiczny-blok-gutenberga","status":"publish","type":"post","link":"https:\/\/wordpress.mediadoma.com\/pl\/samouczek-utworz-suwak-jako-dynamiczny-blok-gutenberga\/","title":{"rendered":"Samouczek: Utw\u00f3rz suwak jako dynamiczny blok Gutenberga"},"content":{"rendered":"\n<p>W tym samouczku om\u00f3wimy spos\u00f3b tworzenia dynamicznego bloku WordPress Gutenberg. Efektem ko\u0144cowym jest suwak pokazuj\u0105cy polecany obraz z wybranych post\u00f3w kategorii. Kod obejmuje u\u017cycie komponentu wy\u017cszego rz\u0119du (<code>withSelect<\/code>) do pobrania wszystkich kategorii w edytorze blok\u00f3w.<\/p>\n<h2>Co zrobimy<\/h2>\n<p>Blok wyrenderuje prosty suwak za pomoc\u0105 skryptu <a href=\"http:\/\/jquery.malsup.com\/cycle2\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">jQuery Cycle2<\/a>. Ale mo\u017cesz u\u017cy\u0107 dowolnego innego skryptu suwaka. Blok wy\u015bwietli wewn\u0105trz edytora list\u0119 wszystkich kategorii, pozwalaj\u0105c u\u017cytkownikowi wybra\u0107 jedn\u0105 kategori\u0119. Wy\u015bwietlaj\u0105c blok w interfejsie, b\u0119dzie on dynamicznie pobiera\u0142 posty z wybranej kategorii i wy\u015bwietla\u0142 ich polecane obrazy jako slajdy. Ten samouczek b\u0119dzie do\u015b\u0107 prosty, umo\u017cliwiaj\u0105c rozwijanie i dostosowywanie suwaka w dowolny spos\u00f3b.<\/p>\n<p>Zdecydowa\u0142em si\u0119 nie renderowa\u0107 pokazu slajd\u00f3w w edytorze. Zwykle upewnij si\u0119, \u017ce renderowanie w edytorze i interfejsie jest takie samo. Ale w przypadku slidera lubi\u0119 zachowa\u0107 prostot\u0119, aby nie zasypywa\u0107 u\u017cytkownika ci\u0105g\u0142ymi animacjami w edytorze.<\/p>\n<p>Blok b\u0119dzie mia\u0142 tylko dwa ustawienia; wyb\u00f3r kategorii i liczby slajd\u00f3w (post\u00f3w). Polecam doda\u0107 wi\u0119cej ustawie\u0144, takich jak pr\u0119dko\u015b\u0107 przesuwania, ustawienia wy\u015bwietlania pigu\u0142ek, strza\u0142ek, tekstu i inne typowe ustawienia suwaka. Samo dodanie tych ustawie\u0144 powinno by\u0107 do\u015b\u0107 proste.<\/p>\n<p>Ca\u0142y kod jest napisany w Javascript ES6 \/ ES2015+. Pami\u0119taj, \u017ce ten kod wymaga Babel do przekszta\u0142cenia i zbudowania ostatecznych plik\u00f3w JavaScript. Sprawd\u017a poni\u017cszy przewodnik, je\u015bli nie wiesz jak.<\/p>\n<h2>Skonfiguruj pliki<\/h2>\n<p>W tym przyk\u0142adzie tworzymy blok wewn\u0105trz motywu. W folderze motywu mam podfolder &#8217; <code>gutenberg\/<\/code>&#8217;, w kt\u00f3rym umie\u015bci\u0142em m\u00f3j <code>package.json<\/code>i <code>webpack-config.js<\/code>. Wewn\u0105trz podfolderu \u201e <code>src\/<\/code>&quot; w tym folderze umieszczam wszystkie moje pliki kompilacji. Konfiguracja mojego pakietu webpack jest skonfigurowana tak, aby umieszcza\u0107 pliki kompilacji w moim podfolderze motywu \u201e <code>assets\/js\/<\/code>&#8222;.<\/p>\n<p>Utw\u00f3rz nowy pusty plik \u017ar\u00f3d\u0142owy w <code>theme-folder\/gutenberg\/src\/block-slider.js<\/code>i skonfiguruj pakiet Webpack, aby utworzy\u0107 plik kompilacji w programie <code>theme-folder\/assets\/js\/block-slider.js<\/code>. Mo\u017cesz dowolnie zmienia\u0107 lokalizacje i\/lub nazwy plik\u00f3w, pami\u0119taj tylko o dostosowaniu poni\u017cszego kodu.<\/p>\n<p>Musimy r\u00f3wnie\u017c pobra\u0107 niezb\u0119dny skrypt slidera. Mo\u017cesz <a href=\"http:\/\/jquery.malsup.com\/cycle2\/download\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">pobra\u0107 Cycle2 pod tym linkiem<\/a> lub u\u017cy\u0107 dowolnego innego skryptu slajd\u00f3w i dostosowa\u0107 poni\u017cszy kod. Umieszczam <code>jquery.cycle2.min.js<\/code>plik w folderze mojego folderu motywu <code>\/assets\/js\/<\/code>.<\/p>\n<p>Przygotuj\u0119 te\u017c ma\u0142y plik CSS, kt\u00f3ry b\u0119dzie \u0142adowany tylko w edytorze. Mamy tylko ma\u0142y kawa\u0142ek stylizacji, aby wyb\u00f3r kategorii by\u0142 optymalny. Tworz\u0119 pusty plik <code>editor-block-slider.css<\/code>i umieszczam go w <code>theme-folder\/assets\/css\/<\/code>.<\/p>\n<p>Na koniec przechodzimy do pliku PHP, kt\u00f3ry jest za\u0142adowany w motywie. Dla uproszczenia robi\u0119 cz\u0119\u015b\u0107 PHP w temacie <code>functions.php<\/code>.<\/p>\n<h2>Zarejestruj blok Gutenberga w PHP<\/h2>\n<p>Wszystkie bloki Gutenberga musz\u0105 by\u0107 zarejestrowane w <code>[register_block_type](https:\/\/developer.wordpress.org\/reference\/functions\/register_block_type\/)()<\/code>. Wol\u0119 wywo\u0142ywa\u0107 go wewn\u0105trz funkcji podpi\u0119tej do <code>init<\/code>. Pierwszym parametrem jest nazwa Twojego bloku wraz z przestrzeni\u0105 nazw. Postanowi\u0142em nazwa\u0107 m\u00f3j skrypt suwaka <code>awp\/slider<\/code>(dostosuj, jak chcesz). Drugi argument to tablica argument\u00f3w.<\/p>\n<p>W ramach tej samej funkcji zarejestruj\u0119 skrypt budowania <code>[wp_register_script](https:\/\/developer.wordpress.org\/reference\/functions\/wp_register_script\/)()<\/code>i zarejestruj\u0119 plik CSS edytora za pomoc\u0105 <code>[wp_register_style](https:\/\/developer.wordpress.org\/reference\/functions\/wp_register_style\/)()<\/code>. Oba te uchwyty zostan\u0105 dodane jako argumenty odpowiednio do \u201e <code>editor_script<\/code>&#8221; i \u201e <code>editor_style<\/code>&#8222;. Je\u015bli chodzi o zale\u017cno\u015bci, doda\u0142em kilka najbardziej podstawowych pakiet\u00f3w dla skryptu, aby upewni\u0107 si\u0119, \u017ce nasz skrypt blokowy jest \u0142adowany we w\u0142a\u015bciwej kolejno\u015bci. Je\u015bli chodzi o styl edytora, u\u017cycie \u201e <code>wp-edit-blocks<\/code>&#8221; jest dobr\u0105 zale\u017cno\u015bci\u0105, aby unikn\u0105\u0107 nadpisania styl\u00f3w.<\/p>\n<p>I wreszcie, poniewa\u017c jest to blok dynamiczny, musimy r\u00f3wnie\u017c doda\u0107 <code>render_callback<\/code>argument \u201e &#8222;, wskazuj\u0105cy na funkcj\u0119 odpowiedzialn\u0105 za renderowanie bloku w interfejsie u\u017cytkownika.<\/p>\n<pre><code>add_action('init', function() {\n    wp_register_script(\n        'awp-block-slider-js', \n        get_template_directory_uri(). '\/assets\/js\/block-slider.js', \n        ['wp-blocks', 'wp-element', 'wp-editor', 'wp-components', 'wp-data']\n    );\n    wp_register_style(\n        'awp-block-slider-style', \n        get_template_directory_uri(). '\/assets\/css\/editor-block-slider.css', \n        ['wp-edit-blocks']\n    );\n\u00a0\n    register_block_type('awp\/slider', [\n        'editor_script' =&gt; 'awp-block-slider-js',\n        'editor_style' =&gt; 'awp-block-slider-style',\n        'render_callback' =&gt; 'awp_gutenberg_slider_render',\n    ]);\n});<\/code><\/pre>\n<p>Na koniec definiujemy funkcj\u0119 render. Do funkcji zwrotnej otrzymujemy dwa parametry; tablic\u0119 atrybut\u00f3w z bloku i zawarto\u015b\u0107 wewn\u0119trzn\u0105 (nieu\u017cywan\u0105 w tym bloku). Po prostu zwr\u00f3c\u0119 jaki\u015b fikcyjny ci\u0105g. Wr\u00f3cimy i rozwiniemy funkcj\u0119 renderowania p\u00f3\u017aniej. Pami\u0119taj, aby zwr\u00f3ci\u0107 ci\u0105g, a nie echo.<\/p>\n<pre><code>function awp_gutenberg_slider_render($attributes, $content) {\n    return 'Slider render comes here.';\n}<\/code><\/pre>\n<p>Powr\u00f3cimy do funkcji renderowania PHP na samym ko\u0144cu tego samouczka. Teraz nadszed\u0142 czas, aby przej\u015b\u0107 do JavaScript!<\/p>\n<h2>Zarejestruj niestandardowy blok Gutenberga w JavaScript<\/h2>\n<p>Otw\u00f3rzmy nasz <code>block-slider.js<\/code>plik \u017ar\u00f3d\u0142owy. W tym momencie uruchomi\u0119 skrypt (<code>npm run start<\/code>), aby przekszta\u0142ci\u0107 wszystko, co robimy w tym pliku, w plik kompilacji. Musimy zarejestrowa\u0107 blok za pomoc\u0105 <code>[registerBlockType](https:\/\/developer.wordpress.org\/block-editor\/developers\/block-api\/block-registration\/)()<\/code>. Sprawd\u017a link, aby zobaczy\u0107 wszystkie mo\u017cliwe argumenty.<\/p>\n<p>Jak zdecydowali\u015bmy w <code>register_block_type()<\/code>PHP, nasz blok nazywa si\u0119 <code>awp\/slider<\/code>. Chcemy r\u00f3wnie\u017c doda\u0107 do bloku dwa atrybuty, jak wspomniano wcze\u015bniej: jeden dla wybranego identyfikatora terminu i jeden dla liczby slajd\u00f3w.<\/p>\n<p>Lubi\u0119 te\u017c dodawa\u0107 funkcjonalno\u015b\u0107 wyr\u00f3wnania blok\u00f3w. Zostanie on dodany automatycznie poprzez dodanie znaku &#8217; <code>align<\/code>&#8217; do <code>supports<\/code>obiektu. Je\u015bli chcesz wszystkie wyr\u00f3wnania blok\u00f3w, mo\u017cesz po prostu ustawi\u0107 <code>align<\/code>na true. Jednak suwak wyr\u00f3wnany do lewej lub do prawej nie ma wi\u0119kszego sensu, wi\u0119c zdefiniuj\u0119 okre\u015blone typy wyr\u00f3wnywania blok\u00f3w, kt\u00f3re obs\u0142uguje ten blok: \u201eWyr\u00f3wnaj do \u015brodka&#8221; (&#8217; <code>center<\/code>&#8217;), \u201eSzeroka szeroko\u015b\u0107&#8221; (&#8217; <code>wide<\/code>&#8217;) i \u201e Pe\u0142na szeroko\u015b\u0107&#8221; (&#8217; <code>full<\/code>&#8217;). Ponadto, aby zdefiniowa\u0107 domy\u015blne wyr\u00f3wnanie i udost\u0119pni\u0107 je z poziomu PHP, dodaj\u0119 &#8217; <code>align<\/code>&#8217; jako atrybut do naszego bloku.<\/p>\n<p>Ustawiam <code>edit<\/code>argument bloku na osobny komponent, kt\u00f3ry nast\u0119pnie stworzymy. I na koniec <code>save<\/code>funkcja po prostu zwraca <code>null<\/code>, poniewa\u017c jest to blok dynamiczny.<\/p>\n<pre><code>const { __ } = wp.i18n;\nconst { registerBlockType } = wp.blocks;\n\u00a0\nregisterBlockType('awp\/slider', {\n    title: __('AWP Slider', 'awp'),\n    icon: 'slides',\n    category: 'common',\n    supports: {\n        align: ['center', 'wide', 'full']\n    },\n    attributes: {\n        align: {\n            type: 'string',\n            default: 'center'\n        },\n        termId: {\n            type: 'number',\n            default: 0\n        },\n        numSlides: {\n            type: 'number',\n            default: 3\n        },\n    },\n    edit: BlockEdit,\n    save:() =&gt; { return null; }\n});<\/code><\/pre>\n<p>Musimy zdefiniowa\u0107 komponent dla <code>edit<\/code>w\u0142a\u015bciwo\u015bci. Przed kodem rejestracyjnym definiuj\u0119 komponent funkcyjny, <code>BlockEdit<\/code>kt\u00f3ry po prostu renderuje a <code>div<\/code>i a <code>Placeholder<\/code>z jakim\u015b fikcyjnym tekstem.<\/p>\n<pre><code>const { __ } = wp.i18n;\nconst { registerBlockType } = wp.blocks;\nconst { Placeholder } = wp.components;\nconst BlockEdit = (props) =&gt; {\n    return(\n        &lt;div className={props.className}&gt;\n            &lt;Placeholder\n                label={__('Slider Category', 'awp')}\n            &gt;\n                Select category comes here.\n            &lt;\/Placeholder&gt;\n        &lt;\/div&gt;\n    );\n}\n\u00a0\nregisterBlockType('awp\/slider', {\n    ...<\/code><\/pre>\n<p><code>[Placeholder](https:\/\/github.com\/WordPress\/gutenberg\/tree\/master\/packages\/components\/src\/placeholder)<\/code>to fajny komponent do renderowania obszaru dla ustawie\u0144 \u2013 i niekoniecznie do rzeczywistego renderowania bloku. Wewn\u0105trz <code>Placeholder<\/code>komponentu renderujemy list\u0119 termin\u00f3w do wyboru.<\/p>\n<p>W tym momencie nasz blok powinien by\u0107 dost\u0119pny w WordPress Gutenberg! Stw\u00f3rzmy nowy post, dodajmy nowy blok i znajd\u017amy nasz blok w kategorii Wsp\u00f3lne. Tak obecnie wygl\u0105da nasz blok:<\/p>\n<p><a href=\"https:\/\/wordpress.mediadoma.com\/wp-content\/uploads\/2022\/01\/post-151906-61e4d14fb8d7b.png\" data-rel=\"lightbox\"><img decoding=\"async\" class=\"SDStudio-light-box-enable SDStudio-editor-tools-md-imp\" src=\"https:\/\/wordpress.mediadoma.com\/wp-content\/uploads\/2022\/01\/post-151906-61e4d14fb8d7b.png\" alt=\"Samouczek: Utw\u00f3rz suwak jako dynamiczny blok Gutenberga\"><\/a><a href=\"https:\/\/wordpress.mediadoma.com\/wp-content\/uploads\/2022\/01\/post-151906-61e4d150ae184.png\" data-rel=\"lightbox\"><img decoding=\"async\" class=\"SDStudio-light-box-enable SDStudio-editor-tools-md-imp\" src=\"https:\/\/wordpress.mediadoma.com\/wp-content\/uploads\/2022\/01\/post-151906-61e4d150ae184.png\" alt=\"Samouczek: Utw\u00f3rz suwak jako dynamiczny blok Gutenberga\"><\/a><\/p>\n<h2>Dodawanie ustawie\u0144 inspektora<\/h2>\n<p>Dodajmy kilka ustawie\u0144 do Inspektora (prawy pasek boczny edytora). Jak wspomniano, nasz blok ma tylko jedno ustawienie; liczba slajd\u00f3w. W tym miejscu zalecam dodanie wi\u0119kszej liczby ustawie\u0144 do bloku suwaka. Pami\u0119taj, aby zarejestrowa\u0107 atrybuty dla ka\u017cdego dodanego ustawienia.<\/p>\n<p>Aby doda\u0107 co\u015b do Inspektora u\u017cywamy komponentu <code>[InspectorControls](https:\/\/github.com\/WordPress\/gutenberg\/tree\/master\/packages\/block-editor\/src\/components\/inspector-controls)<\/code>( ). <code>wp.blockEditor<\/code>Wewn\u0105trz renderujemy <code>[PanelBody](https:\/\/github.com\/WordPress\/gutenberg\/tree\/master\/packages\/components\/src\/panel#panelbody)<\/code>( <code>wp.components<\/code>) w celu dodania nowej sekcji zwijanej. Nast\u0119pnie po prostu renderujemy <code>[RangeControl](https:\/\/github.com\/WordPress\/gutenberg\/tree\/master\/packages\/components\/src\/range-control)<\/code>( <code>wp.components<\/code>), aby utworzy\u0107 ustawienie wej\u015bciowe i wybra\u0107 liczb\u0119 slajd\u00f3w. Ustawiamy minimum na 1 a maksimum na 10. \u0141\u0105czymy zdarzenie <code>value<\/code>i <code>onChange<\/code>z atrybutem <code>numSlides<\/code>.<\/p>\n<pre><code>const { __ } = wp.i18n;\nconst { registerBlockType } = wp.blocks;\nconst { InspectorControls } = wp.blockEditor;\nconst { Placeholder, PanelBody, RangeControl } = wp.components;\n\u00a0\nconst BlockEdit = (props) =&gt; {\n    const { attributes, setAttributes } = props;\n\u00a0\n    return(\n        &lt;div className={props.className}&gt;\n            &lt;InspectorControls&gt;\n                &lt;PanelBody\n                    title={__('Slider Settings', 'awp')}\n                    initialOpen={true}\n                &gt;\n                    &lt;RangeControl\n                        label={__('Number of slides', 'awp')}\n                        value={attributes.numSlides}\n                        onChange={(val) =&gt; setAttributes({ numSlides: val })}\n                        min={1}\n                        max={10}\n                    \/&gt;\n                &lt;\/PanelBody&gt;\n            &lt;\/InspectorControls&gt;\n            &lt;Placeholder\n                ...<\/code><\/pre>\n<p>Dzi\u0119ki powy\u017cszemu kodowi powinni\u015bmy teraz otrzyma\u0107 fajn\u0105 sekcj\u0119 z suwakiem zakresu do ustawiania liczby slajd\u00f3w.<\/p>\n<p><a href=\"https:\/\/wordpress.mediadoma.com\/wp-content\/uploads\/2022\/01\/post-151906-61e4d15191aa1.png\" data-rel=\"lightbox\"><img decoding=\"async\" class=\"SDStudio-light-box-enable SDStudio-editor-tools-md-imp\" src=\"https:\/\/wordpress.mediadoma.com\/wp-content\/uploads\/2022\/01\/post-151906-61e4d15191aa1.png\" alt=\"Samouczek: Utw\u00f3rz suwak jako dynamiczny blok Gutenberga\"><\/a><\/p>\n<p>Ponownie polecam zabaw\u0119 w dodawanie kolejnych ustawie\u0144 do suwaka. Nast\u0119pnym krokiem jest stworzenie elementu do renderowania listy kategorii do wyboru.<\/p>\n<h2>Tworzenie komponentu wyboru kategorii<\/h2>\n<p>Aby nasz kod by\u0142 uporz\u0105dkowany i wielokrotnego u\u017cytku, utw\u00f3rzmy komponent selektora kategorii w osobnym pliku. Wewn\u0105trz folderu build tworz\u0119 nowy plik <code>awp-category-picker.js<\/code>.<\/p>\n<p>Wewn\u0105trz tego pliku definiujemy komponent, kt\u00f3ry b\u0119dzie przechodzi\u0142 przez wszystkie kategorie obecnie w WordPressie i renderuje je w jaki\u015b spos\u00f3b. Aby uzyska\u0107 kategorie, musimy umie\u015bci\u0107 go w tak zwanym komponencie wy\u017cszego rz\u0119du, kt\u00f3ry za po\u015brednictwem rekwizyt\u00f3w dostarczy naszemu komponentowi to, czego potrzebujemy. W tym celu u\u017cyjemy <code>[withSelect](https:\/\/developer.wordpress.org\/block-editor\/packages\/packages-data\/#withSelect)<\/code>. Wewn\u0105trz <code>withSelect<\/code>mo\u017cemy z\u0142o\u017cy\u0107 pro\u015bb\u0119 o pobranie wszystkich kategorii w WordPress za pomoc\u0105 selektora sklepu <code>[select](https:\/\/developer.wordpress.org\/block-editor\/packages\/packages-data\/#select)()<\/code>. Mo\u017cemy u\u017cy\u0107:<\/p>\n<pre><code>select('core').getEntityRecords('taxonomy', '&lt;category_slug&gt;', &lt;args&gt;)<\/code><\/pre>\n<p>aby pobra\u0107 wszystkie terminy w ramach dostarczonej informacji o taksonomii. Je\u015bli nie znasz komponent\u00f3w i selektor\u00f3w wy\u017cszego rz\u0119du w WordPress Gutenberg, mam post, kt\u00f3ry wyja\u015bnia t\u0119 koncepcj\u0119 bardziej szczeg\u00f3\u0142owo: <a href=\"https:\/\/wordpress.mediadoma.com\/pl\/utworz-niestandardowy-blok-gutenberga-czesc-10-pobieranie-postow-i-komponentow-wyzszego-rzedu\/\" title=\"Utw\u00f3rz niestandardowy blok Gutenberga \u2013 cz\u0119\u015b\u0107 10: Pobieranie post\u00f3w i komponent\u00f3w wy\u017cszego rz\u0119du\">Utw\u00f3rz niestandardowy blok Gutenberga \u2013 cz\u0119\u015b\u0107 10: Pobieranie post\u00f3w i komponent\u00f3w wy\u017cszego rz\u0119du<\/a>.<\/p>\n<p>Poniewa\u017c musimy wyeksportowa\u0107 komponent z tego pliku, w zestawieniu umieszczamy kombinacj\u0119 <code>withSelect<\/code>i nasz zdefiniowany komponent <code>export default<\/code>. Nasz <code>CategorySelect<\/code>komponent po prostu zwraca div z jakim\u015b fikcyjnym tekstem, dzi\u0119ki czemu mo\u017cemy zobaczy\u0107, \u017ce to dzia\u0142a. <code>withSelect<\/code>Powinna zawiera\u0107 podpor\u0119 &#8217; &#8217; <code>terms<\/code>do <code>CategorySelect<\/code>. Doda\u0142em a <code>console.log()<\/code>na tym rekwizycie, wi\u0119c wida\u0107, \u017ce dzia\u0142a.<\/p>\n<pre><code>const { withSelect } = wp.data;\n\u00a0\nconst CategorySelect = (props) =&gt; {\n    console.log(props.terms);\n\u00a0\n    return(\n        &lt;div&gt;This is category select&lt;\/div&gt;\n    );\n}\n\u00a0\nexport default withSelect((select, props) =&gt; {\n    return {\n        terms: select('core').getEntityRecords('taxonomy', 'category', {per_page: -1})\n    }\n})(CategorySelect);<\/code><\/pre>\n<p>Ostatni\u0105 rzecz\u0105, kt\u00f3r\u0105 musimy zrobi\u0107, to zaimportowa\u0107 i u\u017cy\u0107 tego komponentu selektora kategorii w naszym bloku niestandardowym.<\/p>\n<p>Wracaj\u0105c <code>block-slider.js<\/code>, najpierw musimy zaimportowa\u0107 komponent na g\u00f3rze pliku. A wewn\u0105trz naszego <code>Placeholder<\/code>komponentu po prostu renderujemy komponent.<\/p>\n<pre><code>const { Placeholder, PanelBody, RangeControl } = wp.components;\n\u00a0\nimport CategorySelect from '.\/awp-category-picker';\n\u00a0\nconst BlockEdit = (props) =&gt; {\n        ...\n            &lt;Placeholder\n                label={__('Slider Category', 'awp')}\n            &gt;\n                &lt;CategorySelect \n                \/&gt;\n            &lt;\/Placeholder&gt;\n        ...<\/code><\/pre>\n<p>Z powy\u017cszym kodem tw\u00f3j blok powinien teraz renderowa\u0107 div z <code>CategorySelect<\/code>komponentu. Je\u015bli otworzysz konsol\u0119 w przegl\u0105darce, powiniene\u015b r\u00f3wnie\u017c zobaczy\u0107 niekt\u00f3re logi. Pami\u0119taj, \u017ce <code>withSelect<\/code>jest to zapytanie asynchroniczne, co oznacza, \u017ce \u200b\u200bmo\u017ce renderowa\u0107 wiele razy. Po raz pierwszy warunki prop to <code>null<\/code>. Ale ostatnie dzienniki powinny ko\u0144czy\u0107 si\u0119 tablic\u0105 termin\u00f3w kategorii.<\/p>\n<p>\u015awietny! Kontynuujmy prac\u0119 z naszym <code>CategorySelect<\/code>komponentem i sprawmy, aby faktycznie renderowa\u0142 list\u0119 termin\u00f3w, umo\u017cliwiaj\u0105c u\u017cytkownikowi wybranie jednego!<\/p>\n<h3>Renderowanie listy termin\u00f3w do wyboru<\/h3>\n<p>Istnieje wiele sposob\u00f3w renderowania listy wybor\u00f3w, na kt\u00f3rej u\u017cytkownik mo\u017ce wybra\u0107 jeden element. Je\u015bli chcesz czego\u015b naprawd\u0119 prostego, mo\u017cesz wyrenderowa\u0107 standardowe menu wyboru (<code>[SelectControl](https:\/\/github.com\/WordPress\/gutenberg\/tree\/master\/packages\/components\/src\/select-control)<\/code>). To zale\u017cy wy\u0142\u0105cznie od Ciebie. Zdecydowa\u0142em si\u0119 na czystsze i przyjemniejsze podej\u015bcie, u\u017cywaj\u0105c <code>[MenuGroup](https:\/\/github.com\/WordPress\/gutenberg\/tree\/master\/packages\/components\/src\/menu-group)<\/code>( <code>wp.components<\/code>) i <code>[MenuItem](https:\/\/github.com\/WordPress\/gutenberg\/tree\/master\/packages\/components\/src\/menu-item)<\/code>( <code>wp.components<\/code>).<\/p>\n<p>Wewn\u0105trz <code>MenuGroup<\/code>komponentu musimy przej\u015b\u0107 przez <code>props.terms<\/code>tablic\u0119, a dla ka\u017cdego elementu chcemy wy\u015bwietli\u0107 <code>MenuItem<\/code>komponent renderuj\u0105cy nazw\u0119 terminu. I oczywi\u015bcie chcemy to renderowa\u0107 tylko wtedy, gdy <code>props.terms<\/code>faktycznie co\u015b zawiera (\u017c\u0105danie asynchroniczne, pami\u0119tasz?).<\/p>\n<pre><code>const { withSelect } = wp.data;\nconst { MenuGroup, MenuItem } = wp.components;\n\u00a0\nconst CategorySelect = (props) =&gt; {\n    const { terms } = props;\n    return(\n        &lt;MenuGroup\n            className=\"awp-categoryselect\"\n        &gt;\n            {terms &amp;&amp; (terms.map((item) =&gt; (&lt;MenuItem\n                        role=\"menuitemradio\"\n                    &gt;\n                        {item.name}\n                    &lt;\/MenuItem&gt;\n                ))\n            )}\n        &lt;\/MenuGroup&gt;\n    );\n}\n\u00a0\nexport default withSelect((select, props) =&gt; {\n    ...<\/code><\/pre>\n<p>Komponentowi nada\u0142em <code>MenuGroup<\/code>klas\u0119 niestandardow\u0105, poniewa\u017c b\u0119dziemy musieli ukierunkowa\u0107 to za pomoc\u0105 CSS. Ustawi\u0142em rekwizyt <code>role<\/code>na <code>MenuItem<\/code>\u201e <code>menuitemradio<\/code>&#8222;, aby mie\u0107 pewno\u015b\u0107, \u017ce w danym momencie mo\u017cna wybra\u0107 tylko jeden. Domy\u015blnie dzia\u0142aj\u0105 one jako pola wyboru, dzi\u0119ki czemu mo\u017cna wybra\u0107 wiele element\u00f3w.<\/p>\n<p>Dzi\u0119ki powy\u017cszemu kodowi nasz blok powinien teraz (po kr\u00f3tkiej sekundzie) wyrenderowa\u0107 \u0142adn\u0105 list\u0119 wszystkich kategorii w twojej instancji WordPressa.<\/p>\n<p>Mo\u017cesz zauwa\u017cy\u0107, \u017ce nasz blok rozszerzy si\u0119, obejmuj\u0105c wszystkie kategorie. Je\u015bli jeste\u015bmy w instancji WordPressa z wieloma kategoriami, szybko staje si\u0119 to problemem. Chcemy si\u0119 upewni\u0107, \u017ce selektor jest kontenerem o maksymalnej wysoko\u015bci, kt\u00f3ry otrzyma pionowy pasek przewijania, je\u015bli istnieje wiele kategorii. Tutaj wkracza nasz plik CSS.<\/p>\n<p>W naszym <code>editor-block-slider.css<\/code>pliku dodaj:<\/p>\n<pre><code>.awp-categoryselect div {\n    max-height: 200px;\n    overflow: hidden scroll;\n    border: 1px solid #b3bcc0;\n}<\/code><\/pre>\n<p>Ten CSS kieruje si\u0119 do <code>div<\/code>wn\u0119trza naszego <code>MenuGroup<\/code>i zapewnia, \u017ce \u200b\u200bnigdy nie przekroczy 200 pikseli. Je\u015bli zawarto\u015b\u0107 strony <code>MenuGroup<\/code>powi\u0119kszy si\u0119 (wi\u0119cej kategorii), poka\u017ce si\u0119 pionowy pasek przewijania. To jest absolutne minimum CSS dla naszego bloku, ale oczywi\u015bcie mo\u017cesz doda\u0107 wi\u0119cej CSS, je\u015bli chcesz.<\/p>\n<p>Ostatni\u0105 rzecz\u0105, kt\u00f3r\u0105 musimy poprawi\u0107 w naszym selektorze kategorii, jest funkcjonalno\u015b\u0107 wy\u015bwietlania aktualnie wybranego elementu i umo\u017cliwienie u\u017cytkownikowi wybrania terminu z listy. W tym celu musimy przekaza\u0107 kilka props do tego komponentu z naszego bloku.<\/p>\n<p>W <code>block-slider.js<\/code>tym celu musimy przekaza\u0107 aktualnie wybrany termin (warto\u015b\u0107 atrybutu <code>termId<\/code>) oraz funkcj\u0119 aktualizuj\u0105c\u0105 wybrany termin (<code>setAttributes<\/code>) jako rekwizyty do naszego komponentu selektora kategorii.<\/p>\n<pre><code>...\n\u00a0\nconst BlockEdit = (props) =&gt; {\n    const { attributes, setAttributes } = props;\n\u00a0\n    const selectTerm = (termId) =&gt; {\n        setAttributes({ termId: termId });\n    }\n\u00a0\n    return(\n        ...\n            &lt;Placeholder\n                label={__('Slider Category', 'awp')}\n            &gt;\n                &lt;CategorySelect \n                    selectedTermId={attributes.termId}\n                    selectTerm={selectTerm}\n                \/&gt;\n            &lt;\/Placeholder&gt;\n        ...<\/code><\/pre>\n<p>W powy\u017cszym kodzie w wierszu <code>#6<\/code>definiujemy funkcj\u0119, kt\u00f3ra po prostu aktualizuje atrybut <code>termId<\/code>. T\u0119 nazw\u0119 funkcji przekazujemy jako prop do <code>CategorySelect<\/code>at line <code>#17<\/code>. W linii <code>#16<\/code>przekazujemy aktualn\u0105 warto\u015b\u0107 <code>termId<\/code>. Dzi\u0119ki temu mo\u017cemy zaktualizowa\u0107 nasz <code>CategorySelect<\/code>komponent, aby odzwierciedla\u0142 wybran\u0105 pozycj\u0119 i pozwoli\u0107 u\u017cytkownikowi na rzeczywisty wyb\u00f3r terminu.<\/p>\n<p>Wracaj\u0105c <code>awp-category-picker.js<\/code>, dodajemy nowe rekwizyty do <code>MenuItem<\/code>. Zwracamy <code>true<\/code>lub <code>false<\/code>dla w\u0142a\u015bciwo\u015bci, <code>isSelected<\/code>czy bie\u017c\u0105cy identyfikator terminu jest taki sam, jak aktualnie wybrany. <code>selectTerm<\/code>Funkcj\u0119 inicjujemy w <code>onClick<\/code>zdarzeniu, przekazuj\u0105c termin ID. Aby zaznaczona pozycja by\u0142a wizualna, warunkowo dodajemy ikon\u0119 przed ka\u017cd\u0105 pozycj\u0105.<\/p>\n<pre><code>...\nconst CategorySelect = (props) =&gt; {\n    const { terms, selectedTermId, selectTerm } = props;\n\u00a0\n    return(\n        &lt;MenuGroup\n            className=\"awp-categoryselect\"\n        &gt;\n            {terms &amp;&amp; (terms.map((item) =&gt; (&lt;MenuItem\n                        role=\"menuitemradio\"\n                        isSelected={item.id == selectedTermId}\n                        icon={item.id == selectedTermId? 'yes': 'no-alt'}\n                        onClick={() =&gt; selectTerm(item.id)}\n                    &gt;\n                        {item.name}\n                    &lt;\/MenuItem&gt;\n                ))\n            )}\n        ...<\/code><\/pre>\n<p>Dzi\u0119ki temu nasz selektor kategorii powinien wygl\u0105da\u0107 tak:<\/p>\n<p><a href=\"https:\/\/wordpress.mediadoma.com\/wp-content\/uploads\/2022\/01\/post-151906-61e4d1525afb7.png\" data-rel=\"lightbox\"><img decoding=\"async\" class=\"SDStudio-light-box-enable SDStudio-editor-tools-md-imp\" src=\"https:\/\/wordpress.mediadoma.com\/wp-content\/uploads\/2022\/01\/post-151906-61e4d1525afb7.png\" alt=\"Samouczek: Utw\u00f3rz suwak jako dynamiczny blok Gutenberga\"><\/a><\/p>\n<p>Lista powinna wyra\u017anie oznacza\u0107 wybrany termin ikon\u0105 wyboru, a zamiast tego mo\u017cna klikn\u0105\u0107 dowolny termin, aby wybra\u0107 ten termin.<\/p>\n<p>To by\u0142o wszystko dla edytora i cz\u0119\u015bci JavaScript! Teraz pozostaje tylko renderowanie frontendu, kt\u00f3re zrobimy w PHP.<\/p>\n<h2>Renderuj blok dynamiczny w PHP<\/h2>\n<p>Zanim zag\u0142\u0119bimy si\u0119 w funkcj\u0119 render, najpierw zajmijmy si\u0119 kilkoma rzeczami.<\/p>\n<p>Najpierw musimy umie\u015bci\u0107 w kolejce skrypt cycle2 w interfejsie u\u017cytkownika, aby nasz kod suwaka faktycznie zamieni\u0142 si\u0119 w suwak. Robimy to za pomoc\u0105 prostej funkcji pod\u0142\u0105czonej do <code>wp_enqueue_scripts<\/code>. Dostosuj poni\u017csze, je\u015bli wybra\u0142e\u015b inny skrypt suwaka.<\/p>\n<pre><code>add_action('wp_enqueue_scripts', function() {\n    wp_enqueue_script(\n        'cycle2-slider-js', \n        get_template_directory_uri(). '\/assets\/js\/jquery.cycle2.min.js', \n        ['jquery'], \n        '', \n        true\n    );\n});<\/code><\/pre>\n<p>Po drugie chcemy wr\u00f3ci\u0107 do <code>register_block_type()<\/code>wywo\u0142ania funkcji. Kiedy zajmujemy si\u0119 blokami dynamicznymi, zdecydowanie powinni\u015bmy doda\u0107 nowy argument; <code>attributes<\/code>. W tym argumencie definiujemy wszystkie atrybuty, kt\u00f3re zdefiniowali\u015bmy <code>registerBlockType<\/code>w JavaScript, w tym ich warto\u015bci domy\u015blne. Je\u015bli tego nie zrobimy, nie wszystkie atrybuty b\u0119d\u0105 dost\u0119pne w naszym wywo\u0142aniu zwrotnym renderowania. Je\u015bli atrybut pozosta\u0142 niezmieniony w edytorze blok\u00f3w, atrybut i jego warto\u015b\u0107 nie b\u0119d\u0105 dost\u0119pne w tablicy atrybut\u00f3w w PHP. Dlatego zalecam, aby zawsze zwraca\u0107 uwag\u0119 na dodanie <code>attributes<\/code>tablicy do <code>register_block_type()<\/code>funkcji PHP podczas pracy z blokami dynamicznymi. Dla naszego bloku wygl\u0105da\u0142oby to tak:<\/p>\n<pre><code>register_block_type('awp\/slider', [\n    'editor_script' =&gt; 'awp-block-slider-js',\n    'editor_style' =&gt; 'awp-block-slider-style',\n    'render_callback' =&gt; 'awp_gutenberg_slider_render',\n    'attributes' =&gt; [\n        'align' =&gt; ['type' =&gt; 'string', 'default' =&gt; 'center'],\n        'termId' =&gt; ['type' =&gt; 'number', 'default' =&gt; 0],\n        'numSlides' =&gt; ['type' =&gt; 'number', 'default' =&gt; 3]\n    ]\n]);<\/code><\/pre>\n<p>Teraz wracamy do naszej funkcji renderowania wywo\u0142a\u0144 zwrotnych <code>awp_gutenberg_slider_render()<\/code>. Wynik zale\u017cy wy\u0142\u0105cznie od Ciebie, zw\u0142aszcza je\u015bli zdecydujesz si\u0119 u\u017cy\u0107 innego skryptu suwaka. Poni\u017cej znajduje si\u0119 prosty przyk\u0142ad.<\/p>\n<p>G\u0142\u00f3wn\u0105 ide\u0105 jest sprawdzenie, czy dany termin zosta\u0142 wybrany (<code>$attributes['termId']<\/code>). Je\u015bli jest wype\u0142niony tworzymy a <code>[WP_Query](https:\/\/developer.wordpress.org\/reference\/classes\/wp_query\/)()<\/code>z argumentami dotycz\u0105cymi liczby post\u00f3w (<code>$attributes['numSlides']<\/code>) oraz wybranego identyfikatora kategorii. Nast\u0119pnie nale\u017cy wygenerowa\u0107 odpowiedni kod HTML do pracy cycle2, zap\u0119tli\u0107 posty i wy\u015bwietli\u0107 ich obrazki jako slajdy.<\/p>\n<pre><code>function awp_gutenberg_slider_render($attributes, $content) {\n    if (empty($attributes['termId'])) {\n        return '';\n    }\n\u00a0\n    $postQuery = new WP_Query([\n        'posts_per_page' =&gt; $attributes['numSlides'],\n        'cat' =&gt; $attributes['termId']\n    ]);\n\u00a0\n    if ($postQuery-&gt;have_posts()) {\n        $output = '&lt;div class=\"wp-block-awp-slider align'. $attributes['align']. '\"&gt;';\n        $output .= '&lt;div class=\"cycle-slideshow\" data-cycle-timeout=4000&gt;';\n        while ($postQuery-&gt;have_posts()) {\n            $postQuery-&gt;the_post();\n\u00a0\n            if (has_post_thumbnail()) {\n                $img_url = get_the_post_thumbnail_url(get_the_ID(), 'loop-thumbnail');\n                $output .= '&lt;img src=\"'. $img_url. '\" \/&gt;';\n            }\n        }\n        wp_reset_postdata();\n        $output .= '&lt;\/div&gt;';\n        $output .= '&lt;\/div&gt;';\n\u00a0\n        return $output;\n\u00a0\n    } else {\n        return '';\n    }\n}<\/code><\/pre>\n<p>Zwr\u00f3\u0107 uwag\u0119, jak doda\u0107 odpowiedni\u0105 klas\u0119 wyr\u00f3wnania bloku w linii <code>#12<\/code>. Wynikiem powinien by\u0107 suwak prezentowanych obraz\u00f3w. Pami\u0119taj, \u017ce jest to podstawowy przyk\u0142ad, kt\u00f3ry ma pewne wady. Na przyk\u0142ad pobieramy ostatnie trzy posty z wybranej kategorii. Ale zak\u0142adaj\u0105c, \u017ce jeden z nich nie ma polecanego obrazu, suwak wy\u015bwietli tylko dwa posty.<\/p>\n<p>Wa\u017cn\u0105 rzecz\u0105 do zapami\u0119tania jest zwracanie ci\u0105gu i nie powtarzanie go. Zalecam r\u00f3wnie\u017c u\u017cywanie w swoim motywie pewnego rodzaju funkcji szablon\u00f3w do renderowania dynamicznych blok\u00f3w, takich jak te. Mo\u017ce szybko sta\u0107 si\u0119 nieuporz\u0105dkowanym naprawianiem i budowaniem kodu HTML jako ci\u0105gu.<\/p>\n<h2>Ostatnie s\u0142owa<\/h2>\n<p>Ten samouczek pokaza\u0142, jak utworzy\u0107 niestandardowy dynamiczny blok WordPress Gutenberg, w kt\u00f3rym renderujesz zawarto\u015b\u0107 frontendu w PHP. Zobaczy\u0142e\u015b te\u017c, jak u\u017cywa\u0107 komponentu wy\u017cszego rz\u0119du <code>withSelect<\/code>do tworzenia zapyta\u0144 o wszystkie terminy kategorii i metody wy\u015bwietlania listy, kt\u00f3r\u0105 mo\u017cna wybra\u0107.<\/p>\n<p>Ca\u0142y powy\u017cszy kod jest napisany tak prosto, jak to tylko mo\u017cliwe. Doda\u0142em tylko absolutne minimum ustawie\u0144. Suwak dzia\u0142a, ale zwykle chcesz wi\u0119cej \u2013 na przyk\u0142ad tworzenie link\u00f3w do slajd\u00f3w, wy\u015bwietlanie tytu\u0142\u00f3w z post\u00f3w, strza\u0142ek suwaka lub opcji dostosowania pr\u0119dko\u015bci lub innych ustawie\u0144 suwaka. Chodzi o to, aby pokaza\u0107 Ci podstawy i u\u0142atwi\u0107 Ci rozbudow\u0119, rozbudow\u0119 i zmian\u0119 w celu dopasowania do potrzeb Twojego projektu.<\/p>\n<p><div id=\"PostUnique_PostSource\" style=\"padding-top: 50px\">\u0179r\u00f3d\u0142o nagrywania:  <a target=\"_blank\" rel=\"noopener nofollow\" href=\"\/\/awhitepixel.com\" class=\"external external_icon\">awhitepixel.com<\/a><\/div><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Samouczek dotycz\u0105cy tworzenia dynamicznego bloku WordPress Gutenberg za pomoc\u0105 funkcji withSelect i renderowania PHP. Efektem ko\u0144cowym jest suwak.<\/p>\n","protected":false},"author":1,"featured_media":151907,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","_wp_rev_ctl_limit":""},"categories":[897,721,721,940,940,897,1110,815,845,845,866,866,815],"tags":[1169],"class_list":{"0":"post-233859","1":"post","2":"type-post","3":"status-publish","4":"format-standard","5":"has-post-thumbnail","6":"hentry","7":"category-kod","8":"category-deweloper","10":"category-gutenberg-7","13":"category-n-a","14":"category-wtyczki","15":"category-samouczki","17":"category-wordpress-7","20":"tag-affiai-pl"},"_links":{"self":[{"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/posts\/233859","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/comments?post=233859"}],"version-history":[{"count":0,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/posts\/233859\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/media\/151907"}],"wp:attachment":[{"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/media?parent=233859"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/categories?post=233859"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/tags?post=233859"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}