{"id":233682,"date":"2023-02-19T20:48:00","date_gmt":"2023-02-19T17:48:00","guid":{"rendered":"https:\/\/wordpress.mediadoma.com\/?p=233682"},"modified":"2022-11-11T08:50:19","modified_gmt":"2022-11-11T05:50:19","slug":"jak-uzyskac-dostep-i-analizowac-bloki-gutenberga-za-pomoca-php","status":"publish","type":"post","link":"https:\/\/wordpress.mediadoma.com\/pl\/jak-uzyskac-dostep-i-analizowac-bloki-gutenberga-za-pomoca-php\/","title":{"rendered":"Jak uzyska\u0107 dost\u0119p i analizowa\u0107 bloki Gutenberga za pomoc\u0105 PHP"},"content":{"rendered":"\n<p>W tym po\u015bcie przyjrzymy si\u0119, jak przeanalizowa\u0107 bloki Gutenberga i wyodr\u0119bni\u0107 okre\u015blone bloki, aby stworzy\u0107 co\u015b innego. Przyjrzymy si\u0119 funkcjom WordPress PHP do parsowania, wyodr\u0119bniania i renderowania wybranych blok\u00f3w.<\/p>\n<p>Jedn\u0105 z zalet nowego edytora Gutenberga w WordPressie jest bardziej uporz\u0105dkowane dane dotycz\u0105ce tre\u015bci post\u00f3w. W dawnych czasach wszystko by\u0142o przechowywane w formacie HTML i nie by\u0142o mo\u017cliwo\u015bci wyodr\u0119bnienia okre\u015blonych fragment\u00f3w tre\u015bci bez bardzo skomplikowanych wyra\u017ce\u0144 regularnych. Ale w przypadku Gutenberga ka\u017cdy element tre\u015bci, czy to akapit, nag\u0142\u00f3wek, obraz, wideo, przycisk, czy kolumna, kt\u00f3ra zawiera inne bloki wewn\u0105trz, jest przechowywany z informacjami, kt\u00f3re m\u00f3wi\u0105 nam, czym jest ten fragment tre\u015bci.<\/p>\n<p>Dzi\u0119ki wbudowanym funkcjom WordPress bardzo \u0142atwo jest pobra\u0107 wszystkie bloki w tre\u015bci posta w tablicy ze wszystkimi ich informacjami. To otwiera mn\u00f3stwo przydatnych funkcji dla tw\u00f3rc\u00f3w motyw\u00f3w. Wystarczy wymieni\u0107 kilka pomys\u0142\u00f3w:<\/p>\n<ul>\n<li>Dynamicznie generuj spis tre\u015bci, pobieraj\u0105c wszystkie nag\u0142\u00f3wki (samouczek poni\u017cej).<\/li>\n<li>Pobierz wszystkie filmy, obrazy lub cytaty u\u017cyte we wszystkich postach, aby zebra\u0107 je i umie\u015bci\u0107 na innej stronie.<\/li>\n<li>Wyodr\u0119bnij pierwszy akapit posta i u\u017cyj go jako fragmentu w archiwach (poradnik poni\u017cej).<\/li>\n<li>Uzyskaj przegl\u0105d wykorzystania okre\u015blonych blok\u00f3w i ich po\u0142o\u017cenia. Za\u0142\u00f3\u017cmy na przyk\u0142ad, \u017ce masz niestandardowy blok reklam i musisz wiedzie\u0107, jak cz\u0119sto jest on u\u017cywany w Twoich postach i jak daleko w tre\u015bci si\u0119 pojawiaj\u0105.<\/li>\n<li>Renderuj bloki posta, ale wyklucz okre\u015blone typy blok\u00f3w.<\/li>\n<li>Sprawd\u017a, czy tre\u015b\u0107 posta zaczyna si\u0119 od filmu i u\u017cyj tego filmu zamiast polecanego obrazu w archiwach.<\/li>\n<li>Je\u015bli u\u017cywasz niestandardowego bloku, kt\u00f3ry zawiera specyfikacje techniczne produkt\u00f3w, mo\u017cesz \u0142atwo utworzy\u0107 stron\u0119 wy\u015bwietlaj\u0105c\u0105 i por\u00f3wnuj\u0105c\u0105 specyfikacje techniczne w postach produkt\u00f3w.<\/li>\n<li>Dynamicznie zbieraj wszystkie pojedyncze obrazy u\u017cyte w po\u015bcie i generuj ich galeri\u0119 na ko\u0144cu lub w innym miejscu.<\/li>\n<\/ul>\n<p>Po prostu wskoczmy w to!<\/p>\n<h2>Przeanalizuj bloki postu<\/h2>\n<p>Do analizy blok\u00f3w u\u017cywamy funkcji WordPress <code>[parse_blocks](https:\/\/developer.wordpress.org\/reference\/functions\/parse_blocks\/)()<\/code>. Jako parametr musisz poda\u0107 ci\u0105g tre\u015bci posta. Je\u015bli jeste\u015b w p\u0119tli lub masz dost\u0119p do obiektu post, po prostu podaj <code>$post-&gt;post_content<\/code>jako parametr funkcji.<\/p>\n<pre><code>$post_id = 1;\n$post = get_post($post_id);\n$blocks = parse_blocks($post-&gt;post_content);<\/code><\/pre>\n<p>Zwrot z <code>parse_blocks()<\/code>jest tablic\u0105, w kt\u00f3rej ka\u017cdy element tablicy jest blokiem. Dla ka\u017cdego elementu bloku masz informacje takie jak typ bloku (klucz &#8217; <code>blockName<\/code>&#8217;), atrybuty bloku (klucz &#8217; <code>attrs<\/code>&#8217;), wewn\u0119trzne bloki dla blok\u00f3w zagnie\u017cd\u017conych, takich jak Kolumny (klucz &#8217; <code>innerBlocks<\/code>&#8217;) oraz dwa elementy dla rzeczywistej zawarto\u015bci bloku (klucze &#8217; <code>innerHTML<\/code>&#8217; i &#8217; <code>innerContent<\/code>&#8217;). Element <code>innerHTML<\/code>jest ci\u0105giem tre\u015bci HTML, podczas gdy <code>innerContent<\/code>jest tablic\u0105 ci\u0105g\u00f3w HTML.<\/p>\n<p>I to wszystko! Przechod\u017a przez zwr\u00f3con\u0105 tablic\u0119 z <code>parse_blocks()<\/code>, aby zrobi\u0107 swoje. Przyjrzymy si\u0119 wi\u0119cej przyk\u0142adom kodu w dalszej cz\u0119\u015bci tego postu.<\/p>\n<h2>Uwaga o postach klasycznych (nie Gutenberga)<\/h2>\n<p>By\u0107 mo\u017ce pracujesz nad starsz\u0105 witryn\u0105 WordPress, kt\u00f3ra utworzy\u0142a posty przed uaktualnieniem do Gutenberga (lub u\u017cy\u0142a wtyczki Disable Gutenberg). W takim przypadku posty te nie b\u0119d\u0105 zawiera\u0142y ustrukturyzowanej tre\u015bci posta, ale raczej ca\u0142a tre\u015b\u0107 posta znajduje si\u0119 w bloku \u201eEdytor klasyczny&quot;.<\/p>\n<p>Tablica zwr\u00f3cona z funkcji <code>parse_blocks()<\/code>w tego rodzaju wpisach zwr\u00f3ci jeden element tablicy blokowej z <code>blockName<\/code>ustawionym na <code>null<\/code>. Pe\u0142na tre\u015b\u0107 HTML posta znajduje si\u0119 wewn\u0105trz <code>innerHTML<\/code>ci\u0105gu tego elementu.<\/p>\n<p>Mo\u017cna \u015bmia\u0142o za\u0142o\u017cy\u0107, \u017ce je\u015bli zwrot posta <code>parse_blocks()<\/code>ma jeden element i <code>blockName<\/code>jest <code>null<\/code>nim, to mamy do czynienia z postem \u201eprzed Gutenbergiem&#8221;. W przeciwnym razie <code>blockName<\/code>zawsze b\u0119dzie zape\u0142niony. Warto o tym pami\u0119ta\u0107 podczas pisania kodu do analizowania blok\u00f3w post\u00f3w i gdy chcesz obs\u0142ugiwa\u0107 starsz\u0105 zawarto\u015b\u0107 WordPressa.<\/p>\n<h2>Renderuj blok<\/h2>\n<p>WordPress oferuje r\u00f3wnie\u017c funkcj\u0119 renderowania okre\u015blonego bloku za pomoc\u0105 <code>[render_block](https:\/\/developer.wordpress.org\/reference\/functions\/render_block\/)()<\/code>. Jako parametr musisz poda\u0107 tablic\u0119 dla bloku, tak jak jedn\u0105 z tych zwr\u00f3conych z <code>parse_blocks()<\/code>g\u00f3ry. Funkcja zwraca ci\u0105g wyrenderowanego kodu HTML, kt\u00f3ry mo\u017cna po prostu wy\u015bwietli\u0107.<\/p>\n<pre><code>$post_id = 1;\n$post = get_post($post_id);\n$blocks = parse_blocks($post-&gt;post_content);\nforeach ($blocks as $block) {\n    echo render_block($block);\n}<\/code><\/pre>\n<p>Powy\u017cszy kod wyrenderuje wszystkie bloki posta, tak jak normalnie podczas renderowania tre\u015bci posta. Zabawna cz\u0119\u015b\u0107 pojawia si\u0119, gdy zaczynamy dodawa\u0107 kod, aby wykluczy\u0107 lub uwzgl\u0119dni\u0107 okre\u015blone bloki, kt\u00f3re nas interesuj\u0105.<\/p>\n<p>Na przyk\u0142ad poni\u017cszy kod wydrukuje tylko bloki akapitu posta:<\/p>\n<pre><code>foreach ($blocks as $block) {\n    if ($block['blockName'] == 'core\/paragraph') {\n        echo render_block($block);\n    }\n}<\/code><\/pre>\n<p>A to wyrenderuje wszystkie bloki, ale wykluczy wszystkie bloki shortcode:<\/p>\n<pre><code>foreach ($blocks as $block) {\n    if ($block['blockName'] != 'core\/shortcode') {\n        echo render_block($block);\n    }\n}<\/code><\/pre>\n<h2>Blokuj nazwy<\/h2>\n<p>Podczas analizowania blok\u00f3w postu najprawdopodobniej b\u0119dziesz musia\u0142 sprawdzi\u0107 typ bloku. S\u0105 do\u015b\u0107 \u0142atwe do odgadni\u0119cia. Na przyk\u0142ad blok akapitu to, dobrze zgad\u0142e\u015b, <code>paragraph<\/code>. Nale\u017cy jednak pami\u0119ta\u0107, \u017ce wszystkie bloki Gutenberga w WordPressie s\u0105 poprzedzone przestrzeni\u0105 nazw. W przypadku podstawowych (domy\u015blnych) blok\u00f3w WordPress, wszystkie s\u0105 poprzedzone przedrostkiem \u201e <code>core\/<\/code>&#8222;. Wyj\u0105tkiem s\u0105 bloki Osad\u017a, kt\u00f3re s\u0105 poprzedzone przedrostkiem \u201e <code>core-embed\/<\/code>&#8222;. Na przyk\u0142ad blok akapitu b\u0119dzie mia\u0142 nazw\u0119 bloku <code>core\/paragraph<\/code>.<\/p>\n<p>Aby unikn\u0105\u0107 dzikiego zgadywania, oto przegl\u0105d domy\u015blnych blok\u00f3w dostarczonych przez WordPress (w momencie pisania tego):<\/p>\n<h3>Wsp\u00f3lne bloki<\/h3>\n<ul>\n<li>Ust\u0119p:<code>core\/paragraph<\/code><\/li>\n<li>Obraz:<code>core\/image<\/code><\/li>\n<li>Nag\u0142\u00f3wek:<code>core\/heading<\/code><\/li>\n<li>Galeria:<code>core\/gallery<\/code><\/li>\n<li>Lista:<code>core\/list<\/code><\/li>\n<li>Cytat:<code>core\/quote<\/code><\/li>\n<li>Audio:<code>core\/audio<\/code><\/li>\n<li>Pokrywa:<code>core\/cover<\/code><\/li>\n<li>Plik:<code>core\/file<\/code><\/li>\n<li>Wideo:<code>core\/video<\/code><\/li>\n<\/ul>\n<h3>Formatowanie<\/h3>\n<ul>\n<li>Wst\u0119pnie sformatowany:<code>core\/preformatted<\/code><\/li>\n<li>Kod:<code>core\/code<\/code><\/li>\n<li>Klasyczny: <code>core\/freeform<\/code><br \/>\n(ale w przypadku post\u00f3w innych ni\u017c Gutenberg b\u0119dzie to <code>null<\/code>, patrz uwaga na temat post\u00f3w innych ni\u017c Gutenberg)<\/li>\n<li>Niestandardowy kod HTML:<code>core\/html<\/code><\/li>\n<li>Cytat:<code>core\/pullquote<\/code><\/li>\n<li>St\u00f3\u0142:<code>core\/table<\/code><\/li>\n<li>Werset:<code>core\/verse<\/code><\/li>\n<\/ul>\n<h3>Uk\u0142ad<\/h3>\n<ul>\n<li>Przycisk:<code>core\/button<\/code><\/li>\n<li>Kolumny:<code>core\/columns<\/code><\/li>\n<li>Wi\u0119cej:<code>core\/more<\/code><\/li>\n<li>Podzia\u0142 strony:<code>core\/nextpage<\/code><\/li>\n<li>Separator:<code>core\/separator<\/code><\/li>\n<li>Odst\u0119pnik:<code>core\/spacer<\/code><\/li>\n<li>Media i tekst:<code>core\/media-text<\/code><\/li>\n<\/ul>\n<h3>Wid\u017cety<\/h3>\n<ul>\n<li>Kr\u00f3tki kod:<code>core\/shortcode<\/code><\/li>\n<li>Archiwa:<code>core\/archives<\/code><\/li>\n<li>Kategorie:<code>core\/categories<\/code><\/li>\n<li>Ostatnie komentarze:<code>core\/latest-omments<\/code><\/li>\n<li>Najnowsze posty:<code>core\/latest-posts<\/code><\/li>\n<\/ul>\n<h3>Osadzenia<\/h3>\n<ul>\n<li>\n<p>Osadza\u0107:<code>core\/embed<\/code><\/p>\n<\/li>\n<li>\n<p>\u015awiergot:<code>core-embed\/twitter<\/code><\/p>\n<\/li>\n<li>\n<p>Youtube:<code>core-embed\/youtube<\/code><\/p>\n<\/li>\n<li>\n<p>Facebook:<code>core-embed\/facebook<\/code><\/p>\n<\/li>\n<li>\n<p>Instagram:<code>core-embed\/instagram<\/code><\/p>\n<\/li>\n<li>\n<p>WordPress:<code>core-embed\/wordpress<\/code><\/p>\n<\/li>\n<li>\n<p>SoundCloud:<code>core-embed\/soundcloud<\/code><\/p>\n<\/li>\n<li>\n<p>Spotify:<code>core-embed\/spotify<\/code><\/p>\n<\/li>\n<li>\n<p>Flickr:<code>core-embed\/flickr<\/code><\/p>\n<\/li>\n<li>\n<p>Vimeo:<code>core-embed\/vimeo<\/code><\/p>\n<\/li>\n<li>\n<p>Animo:<code>core-embed\/animoto<\/code><\/p>\n<\/li>\n<li>\n<p>Chmura:<code>core-embed\/cloudup<\/code><\/p>\n<\/li>\n<li>\n<p>Sygna\u0142 t\u0142umu:<code>core-embed\/crowdsignal<\/code><\/p>\n<\/li>\n<li>\n<p>Ruch dzienny:<code>core-embed\/dailymotion<\/code><\/p>\n<\/li>\n<li>\n<p>Hulu:<code>core-embed\/hulu<\/code><\/p>\n<\/li>\n<li>\n<p>Obrazek:<code>core-embed\/imgur<\/code><\/p>\n<\/li>\n<li>\n<p>Kwestia:<code>core-embed\/issuu<\/code><\/p>\n<\/li>\n<li>\n<p>Kickstarter:<code>core-embed\/kickstarter<\/code><\/p>\n<\/li>\n<li>\n<p>Meetup.com:<code>core-embed\/meetup-com<\/code><\/p>\n<\/li>\n<li>\n<p>Mixcloud:<code>core-embed\/mixcloud<\/code><\/p>\n<\/li>\n<li>\n<p>Reddit:<code>core-embed\/reddit<\/code><\/p>\n<\/li>\n<li>\n<p>Nar\u00f3d pog\u0142osu:<code>core-embed\/reverbnation<\/code><\/p>\n<\/li>\n<li>\n<p>Prezentacja ekranu:<code>core-embed\/screencast<\/code><\/p>\n<\/li>\n<li>\n<p>Scribd:<code>core-embed\/scribd<\/code><\/p>\n<\/li>\n<li>\n<p>Udost\u0119pnianie slajd\u00f3w:<code>core-embed\/slideshare<\/code><\/p>\n<\/li>\n<li>\n<p>Kubek:<code>core-embed\/smugmug<\/code><\/p>\n<\/li>\n<li>\n<p>Pok\u0142ad g\u0142o\u015bnika:<code>core-embed\/speaker<\/code><\/p>\n<\/li>\n<li>\n<p>PRZETRZ\u0104SA\u0106:<code>core-embed\/ted<\/code><\/p>\n<\/li>\n<li>\n<p>Tumblr:<code>core-embed\/tumblr<\/code><\/p>\n<\/li>\n<li>\n<p>WideoPrasa:<code>core-embed\/videopress<\/code><\/p>\n<\/li>\n<li>\n<p>wordpress.tv:<code>core-embed\/wordpress-tv<\/code><\/p>\n<\/li>\n<li>\n<p>Amazon Kindle:<code>core-embed\/amazon-kindle<\/code><\/p>\n<\/li>\n<\/ul>\n<h2>Przyk\u0142ad kodu: pobierz pierwszy akapit posta jako fragment<\/h2>\n<p>Dobrze napisany post powinien zaczyna\u0107 si\u0119 od akapitu, kt\u00f3ry przedstawia, o czym jest post i zach\u0119ca ludzi do dalszego czytania. S\u0105 one idealne do wykorzystania jako fragmenty zamiast polega\u0107 na funkcji automatycznego fragmentu w WordPress!<\/p>\n<p>Jest to funkcja, kt\u00f3r\u0105 mo\u017cesz doda\u0107 do swojego motywu <code>functions.php<\/code>, kt\u00f3ra zwr\u00f3ci pierwszy akapit posta. Je\u015bli nie podano wiadomo\u015bci, b\u0119dzie to odnosi\u0107 si\u0119 do globalnego obiektu wiadomo\u015bci. Obs\u0142uguje r\u00f3wnie\u017c posty spoza Gutenberga, zwracaj\u0105c dla nich rzeczywisty fragment WordPressa.<\/p>\n<pre><code>function awp_get_excerpt($post=false) {\n    if (!$post) { \n        global $post;\n    }\n    if (!$post) { return ''; }\n    $excerpt = '';\n    $blocks = parse_blocks($post-&gt;post_content);\n    if (count($blocks) == 1 &amp;&amp; $blocks[0]['blockName'] == null) {  \/\/ Non-Gutenberg posts\n        $excerpt = get_the_excerpt($post-&gt;ID);\n    } else {\n        foreach ($blocks as $block) {\n            if ($block['blockName'] == 'core\/paragraph') {\n                $excerpt = strip_tags($block['innerHTML']);\n                break;\n            }\n        }\n    }\n    return \"&lt;div class='excerpt'&gt;$excerpt&lt;\/div&gt;\";\n}<\/code><\/pre>\n<p>Po <code>parse_blocks()<\/code>wywo\u0142aniu funkcji sprawdzamy, czy post zawiera nieprawid\u0142owe dane bloku (post zosta\u0142 utworzony przed Gutenbergiem) i zwracamy fragment posta, je\u015bli tak jest. W przeciwnym razie przechodzimy przez bloki posta, znajdujemy pierwszy blok akapitu i zwracamy jego <code>innerHTML<\/code>. Na samym ko\u0144cu zwracamy napis z (jest to opcjonalne) <code>&lt;div&gt;<\/code>wok\u00f3\u0142 niego.<\/p>\n<p>Aby skorzysta\u0107 z tej funkcji wystarczy zadzwoni\u0107:<\/p>\n<pre><code>echo awp_get_excerpt();<\/code><\/pre>\n<p>Zak\u0142adaj\u0105c, \u017ce wywo\u0142anie funkcji jest umieszczone gdzie\u015b, gdzie znajduje si\u0119 <code>$post<\/code>obiekt globalny, na przyk\u0142ad wewn\u0105trz p\u0119tli. Je\u015bli chcesz okre\u015bli\u0107 post, podaj obiekt post jako parametr wywo\u0142ania funkcji:<\/p>\n<pre><code>$post_id = 1;\n$post = get_post($post_id);\necho awp_get_excerpt($post);<\/code><\/pre>\n<h2>Przyk\u0142ad: Utw\u00f3rz spis tre\u015bci z nag\u0142\u00f3wk\u00f3w posta<\/h2>\n<p>Mo\u017cesz automatycznie i dynamicznie generowa\u0107 spis tre\u015bci na podstawie blok\u00f3w nag\u0142\u00f3wk\u00f3w posta. Proces jest do\u015b\u0107 prosty; przeanalizuj bloki posta i znajd\u017a wszystkie bloki typu <code>core\/heading<\/code>. Ale mo\u017cemy p\u00f3j\u015b\u0107 o krok dalej i w\u0142\u0105czy\u0107 poziomy; np. umieszczaj\u0105c <code>h3<\/code>jako podtytu\u0142 pod <code>h2<\/code>i tak dalej.<\/p>\n<p>Blok nag\u0142\u00f3wka zawiera informacje o jego poziomie w elemencie tablicy atrybut\u00f3w (klucz \u201e <code>attrs<\/code>&#8222;). Wewn\u0105trz <code>attrs<\/code>tablicy by\u0142by to element tablicy z kluczem \u201e <code>level<\/code>&#8221; i liczb\u0105 ca\u0142kowit\u0105 oznaczaj\u0105c\u0105 poziom. A <code>h3<\/code>mia\u0142by \u201e <code>level<\/code>&#8221; warto\u015b\u0107 <code>3<\/code>, a <code>h4<\/code>mia\u0142by \u201e <code>level<\/code>&#8221; <code>4<\/code>i tak dalej.<\/p>\n<p>Pami\u0119taj jednak, \u017ce <code>attrs<\/code>dla nag\u0142\u00f3wka bloki mog\u0105 by\u0107 puste! Dzieje si\u0119 tak, gdy autor nie zmieni\u0142 typu nag\u0142\u00f3wka w stosunku do domy\u015blnego w ustawieniach bloku. Aby to obej\u015b\u0107, musimy przyj\u0105\u0107 pewne za\u0142o\u017cenia. Jako domy\u015blne b\u0119d\u0105 nag\u0142\u00f3wki <code>h2<\/code>(chyba \u017ce zmieni\u0142e\u015b to w swoim motywie). Mo\u017cemy wi\u0119c za\u0142o\u017cy\u0107, \u017ce je\u015bli blok nag\u0142\u00f3wka nie ma atrybutu poziomu, jest to <code>h2<\/code>. W przeciwnym razie uzyskamy informacje o poziomie z atrybut\u00f3w.<\/p>\n<p>Je\u015bli naprawd\u0119 sprostasz wyzwaniu, zapraszam do ulepszenia poni\u017cszego kodu. Problem z wygenerowaniem odpowiedniej ustrukturyzowanej <code>ol<\/code>listy polega na tym, \u017ce nie mo\u017cemy kontrolowa\u0107, w jaki spos\u00f3b autor ustrukturyzuje swoje tytu\u0142y. Mog\u0105 bardzo dobrze zwariowa\u0107 i zacz\u0105\u0107 od <code>h4<\/code>nag\u0142\u00f3wka, a zaraz potem przej\u015b\u0107 od razu do <code>h2<\/code>nag\u0142\u00f3wka. I nagle mieszaj\u0105 si\u0119 <code>h1<\/code>w \u015brodku. Moje rozwi\u0105zanie polega wi\u0119c na wygenerowaniu p\u0142askiej <code>ol<\/code>listy i podaniu informacji o poziomie w klasach element\u00f3w listy. Nast\u0119pnie za pomoc\u0105 sprytnego CSS mo\u017cesz odpowiednio wci\u0105\u0107 elementy listy za pomoc\u0105 lewego dope\u0142nienia.<\/p>\n<h3>Kod<\/h3>\n<p>Oto funkcja spisu tre\u015bci:<\/p>\n<pre><code>function awp_table_of_contents($post=false) {\n    if (!$post) {\n        global $post;\n    }\n    if (!$post) { return ''; }\n    $headings = [];\n    $blocks = parse_blocks($post-&gt;post_content);\n    if (count($blocks) == 1 &amp;&amp; $blocks[0]['blockName'] == null) {  \/\/ Non-Gutenberg posts\n        return '';\n    } else {\n        foreach ($blocks as $block) {\n            if ($block['blockName'] == 'core\/heading') {\n                $level = (isset($block['attrs']['level']))? $block['attrs']['level']: 2;  \/\/ h2 as default\n                $headings[] = ['title' =&gt; wp_strip_all_tags($block['innerHTML']), 'level' =&gt; $level];\n            }\n        }\n    }\n\u00a0\n    if (empty($headings)) {  \/\/ No headings found in post\n        return '';\n    }\n\u00a0\n    $toc = '&lt;ol class=\"table-of-contents\"&gt;';\n    foreach ($headings as $heading) {\n        $toc .= '&lt;li class=\"heading-level-'. $heading['level']. '\"&gt;'. $heading['title']. '&lt;\/li&gt;';\n    }\n    $toc .= '&lt;\/ol&gt;';\n    return $toc;\n}<\/code><\/pre>\n<p>Funkcja zaczyna si\u0119 od obs\u0142ugi posta i parsowania jego blok\u00f3w. Na linii <code>#9<\/code>przyjmujemy stanowiska nie-Gutenberga. Funkcja kontynuuje p\u0119tl\u0119 przez wszystkie bloki i za ka\u017cdym razem, gdy znajdzie blok nag\u0142\u00f3wka, zostanie dodana do naszej <code>$headings<\/code>tablicy. U\u017cywamy <code>[wp_strip_all_tags](https:\/\/developer.wordpress.org\/reference\/functions\/wp_strip_all_tags\/)()<\/code>do usuwania tag\u00f3w HTML z tytu\u0142\u00f3w. Dodajemy r\u00f3wnie\u017c informacje o poziomie do naszej tablicy, gdzie domy\u015blnie jest ustawione, <code>2<\/code>je\u015bli atrybuty s\u0105 puste.<\/p>\n<p>Po p\u0119tli blokowej <code>$headings<\/code>tablica powinna zawiera\u0107 kolejno wszystkie nag\u0142\u00f3wki posta. Mo\u017cemy wtedy po prostu wygenerowa\u0107 ci\u0105g HTML i wypisa\u0107 jego zawarto\u015b\u0107. Jak wspomnia\u0142em, generuj\u0119 nazw\u0119 klasy na ka\u017cdym elemencie z informacj\u0105 o poziomie nag\u0142\u00f3wka, dzi\u0119ki czemu mo\u017cemy stworzy\u0107 iluzj\u0119 ustrukturyzowanej listy za pomoc\u0105 CSS.<\/p>\n<p>Podobnie jak w przypadku funkcji fragmentu powy\u017cej, mo\u017cemy wywo\u0142a\u0107 t\u0119 funkcj\u0119, gdy znajdujemy si\u0119 w p\u0119tli, w ten spos\u00f3b:<\/p>\n<pre><code>echo awp_table_of_contents();<\/code><\/pre>\n<p>Lub je\u015bli jeste\u015bmy poza p\u0119tl\u0105 lub chcemy okre\u015bli\u0107 post;<\/p>\n<pre><code>$post_id = 1;\n$post = get_post($post_id);\necho awp_table_of_contents($post);<\/code><\/pre>\n<p>Spowoduje to wygenerowanie listy wygl\u0105daj\u0105cej mniej wi\u0119cej tak:<\/p>\n<p><a href=\"https:\/\/wordpress.mediadoma.com\/wp-content\/uploads\/2022\/01\/post-152586-61e4e13930788.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-152586-61e4e13930788.png\" alt=\"Jak uzyska\u0107 dost\u0119p i analizowa\u0107 bloki Gutenberga za pomoc\u0105 PHP\" ><\/a><\/p>\n<h2>Wniosek<\/h2>\n<p>Jak widzieli\u015bmy w przypadku ustrukturyzowanej, bogatej tre\u015bci post\u00f3w, kt\u00f3r\u0105 umo\u017cliwia Gutenberg, mo\u017cemy bardzo \u0142atwo znale\u017a\u0107 i wyodr\u0119bni\u0107 okre\u015blone cz\u0119\u015bci tre\u015bci post\u00f3w. Wr\u00f3\u0107 do listy przyk\u0142ad\u00f3w, o kt\u00f3rych wspomnia\u0142em na pocz\u0105tku postu. Nie ma ogranicze\u0144 co do tego, co mo\u017cesz zrobi\u0107 jako programista motyw\u00f3w. Zale\u017cy to tylko od tego, czego potrzebuje Tw\u00f3j motyw lub witryna WordPress (lub co by\u0142oby po prostu fajne).<\/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>Szczeg\u00f3\u0142owe spojrzenie na to, jak parsowa\u0107 bloki posta za pomoc\u0105 funkcji WordPress PHP do parsowania, filtrowania i renderowania okre\u015blonych blok\u00f3w.<\/p>\n","protected":false},"author":1,"featured_media":152587,"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":["post-233682","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-kod","category-deweloper","category-gutenberg-7","category-n-a","category-wtyczki","category-samouczki","category-wordpress-7","tag-affiai-pl"],"_links":{"self":[{"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/posts\/233682","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=233682"}],"version-history":[{"count":0,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/posts\/233682\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/media\/152587"}],"wp:attachment":[{"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/media?parent=233682"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/categories?post=233682"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/tags?post=233682"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}