{"id":228206,"date":"2022-10-16T15:27:00","date_gmt":"2022-10-16T12:27:00","guid":{"rendered":"https:\/\/wordpress.mediadoma.com\/?p=228206"},"modified":"2022-11-09T01:17:33","modified_gmt":"2022-11-08T22:17:33","slug":"korzystanie-z-opcji-przechowywania-danych-w-edytorze-blokow-wordpress-gutenberg","status":"publish","type":"post","link":"https:\/\/wordpress.mediadoma.com\/pl\/korzystanie-z-opcji-przechowywania-danych-w-edytorze-blokow-wordpress-gutenberg\/","title":{"rendered":"Korzystanie z opcji przechowywania danych w edytorze blok\u00f3w WordPress (Gutenberg)"},"content":{"rendered":"\n<p>Wcze\u015bniej badali\u015bmy przechowywanie danych edytora blok\u00f3w WordPress (Gutenberg) w <a href=\"https:\/\/wholesomecode.ltd\/guides\/creating-plugin-wordpress-gutenberg\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">atrybutach bloku<\/a> i w <a href=\"https:\/\/wholesomecode.ltd\/guides\/post-meta-fields-store-attributes-wordpress-gutenberg\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">meta postu<\/a>, ale czy wiesz, \u017ce mo\u017cesz przechowywa\u0107 i pobiera\u0107 z tabeli opcji WordPress, importuj\u0105c <code>api<\/code>z <code>@wordpress\/api<\/code>.<\/p>\n<p>W tym przewodniku przyjrzymy si\u0119, co klasycznie pisa\u0142by\u015b w PHP jako <code>update_option<\/code>i <code>get_option<\/code>.<\/p>\n<p>Aby to zaimplementowa\u0107, musimy skorzysta\u0107 z cyklu \u017cycia Reacta, wi\u0119c przyjrzymy si\u0119 tworzeniu komponentu React poprzez import <code>Component<\/code>z <code>@wordpress\/element<\/code>.<\/p>\n<h2>Warunki wst\u0119pne<\/h2>\n<ul>\n<li>Zapoznaj si\u0119 z <a href=\"https:\/\/wholesomecode.ltd\/guides\/creating-plugin-wordpress-gutenberg\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">tworzeniem wtyczek do WordPress Gutenberg<\/a><\/li>\n<li>Poznaj <a href=\"https:\/\/wholesomecode.ltd\/guides\/php-render-block-wordpress-gutenberg\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">dynamiczne bloki i renderowanie po stronie serwera<\/a><\/li>\n<li>Zrozum, jak <a href=\"https:\/\/wholesomecode.ltd\/guides\/custom-meta-boxes-wordpress-gutenberg\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">tworzy\u0107 metaboxy w Gutenberg<\/a><\/li>\n<\/ul>\n<p>To ostatnie wymaganie jest przydatne dla interfejsu u\u017cytkownika, kt\u00f3rego b\u0119dziemy u\u017cywa\u0107 w tym przewodniku, jednak w rzeczywistych aplikacjach prawdopodobnie u\u017cyjesz tej metody na pasku bocznym lub stronie opcji.<\/p>\n<h2>Zarejestruj opcje w PHP<\/h2>\n<p>Zanim b\u0119dziemy mogli u\u017cy\u0107 opcji w JavaScript, musimy upewni\u0107 si\u0119, \u017ce zarejestrowali\u015bmy j\u0105 w PHP za pomoc\u0105 <code>register_setting<\/code>i \u017ce <code>show_in_rest<\/code>argument zosta\u0142 ustawiony na true.<\/p>\n<p>Kontynuuj\u0105c <a href=\"https:\/\/wholesomecode.ltd\/guides\/php-render-block-wordpress-gutenberg\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">przewodnik po blokach dynamicznych<\/a>, otw\u00f3rz g\u0142\u00f3wny plik PHP wtyczki (w tym przypadku <code>wholesome-plugin.php<\/code>) i dodaj nast\u0119puj\u0105cy kod na ko\u0144cu tego pliku po wszystkich innych funkcjach:<\/p>\n<pre><code>function wholesomecode_wholesome_plugin_register_settings() {\n    register_setting(\n        'wholesomecode_wholesome_plugin_settings',\n        'wholesomecode_wholesome_plugin_example_text',\n        [\n            'default'       =&gt; '',\n            'show_in_rest'  =&gt; true,\n            'type'          =&gt; 'string',\n        ]\n    );\n}\nadd_action( 'init', 'wholesomecode_wholesome_plugin_register_settings' );\n<\/code><\/pre>\n<p>Ten kod rejestruje pole meta wywo\u0142ywane <code>wholesomecode_wholesome_plugin_block_text<\/code>dla <code>wholesomecode_wholesome_plugin_settings<\/code>grupy opcji. Zapewnia r\u00f3wnie\u017c, \u017ce interfejs API REST mo\u017ce uzyska\u0107 dost\u0119p do tego pola meta z <code>show_in_rest<\/code>warto\u015bci\u0105 ustawion\u0105 na true.<\/p>\n<h2>Utw\u00f3rz komponent<\/h2>\n<p>Otw\u00f3rz <code>\/src\/edit.js<\/code>plik, zmienimy nieco struktur\u0119 tego pliku, aby\u015bmy mogli wypisa\u0107 nasze <code>Component<\/code>.<\/p>\n<p>Wytnij i wklej ca\u0142y ten blok kodu do <code>\/src\/edit.js<\/code>pliku, om\u00f3wimy to za chwil\u0119:<\/p>\n<pre><code>import { __ } from '@wordpress\/i18n';\nimport { useBlockProps } from '@wordpress\/block-editor';\nimport {\n    Panel,\n    PanelBody,\n    TextControl,\n} from '@wordpress\/components';\nimport { Component } from '@wordpress\/element';\n\nimport '.\/editor.scss';\n\nclass OptionsExample extends Component {\n    constructor() {\n        super( ...arguments );\n        this.state = { exampleText: '' };\n    }\n\n    render() {\n        const { exampleText } = this.state;\n        return (&lt;Panel&gt;\n                &lt;PanelBody\n                    title={ __( 'Example Meta Box', 'wholesome-plugin') }\n                    icon=\"admin-plugins\"\n                &gt;\n                    &lt;TextControl\n                        help={ __( 'This is an example text field.', 'wholesome-plugin') }\n                        label={ __( 'Example Text', 'wholesome-plugin') }\n                        onChange={ (exampleText) =&gt; this.setState( { exampleText }) }\n                        value={ exampleText }\n                    \/&gt;\n                &lt;\/PanelBody&gt;\n            &lt;\/Panel&gt;) }\n}\n\nexport default function Edit( props) {\n    return (&lt;div { ...useBlockProps() }&gt;\n            &lt;OptionsExample { ...props }\/&gt;\n        &lt;\/div&gt;\n    );\n}\n<\/code><\/pre>\n<p>Mo\u017cesz rozpozna\u0107, \u017ce interfejs u\u017cytkownika, kt\u00f3ry wprowadzili\u015bmy, jest dok\u0142adnie taki sam, jak w przewodniku <a href=\"https:\/\/wholesomecode.ltd\/guides\/custom-meta-boxes-wordpress-gutenberg\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">Gutenberg Meta Box<\/a>, w kt\u00f3rym u\u017cyli\u015bmy atrybut\u00f3w post meta. Mo\u017cesz r\u00f3wnie\u017c zauwa\u017cy\u0107, \u017ce jeszcze nie pobieramy ani nie ustawiamy informacji za pomoc\u0105 opcji, a zamiast tego u\u017cywamy tylko komponentu <code>state<\/code>.<\/p>\n<h3>Korzystanie ze stanu<\/h3>\n<p>Powodem, dla kt\u00f3rego stworzyli\u015bmy niestandardowy komponent, a nast\u0119pnie przekazali\u015bmy go do naszej <code>Edit<\/code>funkcji, jest mo\u017cliwo\u015b\u0107 wykorzystania stanu. Zrobili\u015bmy to, poniewa\u017c:<\/p>\n<ul>\n<li>Stworzymy funkcj\u0119 do \u0142adowania opcji z API i musimy to przechowywa\u0107 w stanie, aby nasze komponenty mog\u0142y to odczyta\u0107<\/li>\n<li>Nie chcemy, aby API aktualizowa\u0142o opcje, gdy tylko tekst zmieni si\u0119 w naszym polu tekstowym, wi\u0119c potrzebujemy funkcji, aby zapisa\u0107 stan w opcjach przez API po zapisaniu postu<\/li>\n<\/ul>\n<p>Korzystanie ze stanu jest do\u015b\u0107 proste. W konstruktorze inicjujemy stan tak:<\/p>\n<pre><code>this.state = { exampleText: '' };\n<\/code><\/pre>\n<p>A w komponencie uzyskujemy do niego dost\u0119p podobny do tego, w jaki uzyskali\u015bmy dost\u0119p do atrybut\u00f3w w poprzednim przewodniku:<\/p>\n<pre><code>const { exampleText } = this.state;\n<\/code><\/pre>\n<p>R\u00f3\u017cnica polega na tym, \u017ce w naszej <code>onChange<\/code>metodzie zamiast <code>setAttributes<\/code>u\u017cywa\u0107 <code>this.setState<\/code>.<\/p>\n<h3>Pobieranie opcji z API<\/h3>\n<p>W g\u00f3rnej cz\u0119\u015bci importu dokumentu <code>api<\/code>z <code>@wordpress\/api<\/code>:<\/p>\n<pre><code>import api from '@wordpress\/api';\n<\/code><\/pre>\n<p>Dodaj now\u0105 w\u0142a\u015bciwo\u015b\u0107 do miejsca, w kt\u00f3rym zainicjowano stan <code>isAPILoaded<\/code>. B\u0119dzie nam to potrzebne, aby upewni\u0107 si\u0119, \u017ce nie spr\u00f3bujemy uzyska\u0107 dost\u0119pu do interfejsu API ani nie wyrenderowa\u0107 komponentu przed za\u0142adowaniem interfejsu API.<\/p>\n<pre><code>this.state = {\n  exampleText: '',\n  isAPILoaded: false,\n};\n<\/code><\/pre>\n<p>Teraz wewn\u0105trz utworzonego przez nas komponentu dodaj blok kodu pod konstruktorem o nazwie <code>componentDidMount<\/code>. Jest to metoda cyklu \u017cycia Reacta, kt\u00f3ra jest wywo\u0142ywana po dodaniu komponentu do DOM.<\/p>\n<p>W tym bloku kodu dodaj nast\u0119puj\u0105ce elementy:<\/p>\n<pre><code>componentDidMount() {\n  api.loadPromise.then(() =&gt; {\n    this.settings = new api.models.Settings();\n\n    const { isAPILoaded } = this.state;\n\n    if (isAPILoaded === false) {\n      this.settings.fetch().then( (response) =&gt; {\n        this.setState( {\n          exampleText: response[ 'wholesomecode_wholesome_plugin_example_text' ],\n          isAPILoaded: true,\n        } );\n      } );\n    }\n  } );\n}\n<\/code><\/pre>\n<p>Tutaj mamy dost\u0119p do opcji, kt\u00f3r\u0105 zarejestrowali\u015bmy wcze\u015bniej z <code>register_setting<\/code>funkcj\u0105.<\/p>\n<p>Ten blok kodu wykonuje nast\u0119puj\u0105ce czynno\u015bci:<\/p>\n<ul>\n<li>Pobiera ustawienia z interfejsu API ustawie\u0144 WordPress Guttenberg.<\/li>\n<li>Dostaje <code>isAPILoaded<\/code>od sate<\/li>\n<li>Je\u015bli API nie zosta\u0142o za\u0142adowane, pobiera ustawienia z API w a<code>response<\/code><\/li>\n<li>Nast\u0119pnie ustawiamy stan, aby zaktualizowa\u0107 stan z opcj\u0105, do kt\u00f3rej chcemy uzyska\u0107 dost\u0119p i ustawiamy <code>isAPILoaded<\/code>stan na true<\/li>\n<\/ul>\n<h3>Zatrzymaj renderowanie blok\u00f3w bez ustawie\u0144<\/h3>\n<p>Nie chcemy, aby nasz blok by\u0142 renderowany przed wype\u0142nieniem ustawie\u0144. Aby si\u0119 tym zaj\u0105\u0107, mo\u017cemy zaimportowa\u0107 PlaceHolder i Spinner z <code>$wordpress\/components<\/code>:<\/p>\n<pre><code>import {\n    Panel,\n    PanelBody,\n    Placeholder,\n    Spinner,\n    TextControl,\n} from '@wordpress\/components';\n<\/code><\/pre>\n<p>Nast\u0119pnie w metodzie renderowania komponentu upewnij si\u0119, \u017ce otrzymujesz <code>isAPILoaded<\/code>ze stanu i wypisujesz <code>Placeholder<\/code>i <code>Spinner<\/code>je\u015bli nie:<\/p>\n<pre><code>const {\n  exampleText,\n  isAPILoaded,\n} = this.state;\n\nif (! isAPILoaded) {\n  return (&lt;Placeholder&gt;\n      &lt;Spinner \/&gt;\n    &lt;\/Placeholder&gt;\n  );\n}\n<\/code><\/pre>\n<p>W ten spos\u00f3b, je\u015bli opcje nie zosta\u0142y za\u0142adowane, otrzymamy \u0142adny symbol zast\u0119pczy do momentu za\u0142adowania komponentu:<\/p>\n<p>Symbol zast\u0119pczy i Spinner<\/p>\n<h3>Pod\u0142\u0105czanie do Gutenberga na Save<\/h3>\n<p>Teraz, gdy czytamy opcje z tabeli opcji, potrzebujemy sposobu na zapisanie tych opcji, gdy je zmienimy. Aby to zrobi\u0107, udajemy si\u0119 <code>subscribe<\/code>do magazynu danych WordPress Gutenberg, kt\u00f3ry wska\u017ce, kiedy co\u015b si\u0119 zmieni\u0142o.<\/p>\n<p>Korzystaj\u0105c z tego, utworzymy s\u0142uchacza, kiedy post zostanie zapisany i zapiszemy nasze ustawienia, gdy to si\u0119 stanie.<\/p>\n<p>Aby to zrobi\u0107, importuj <code>subscribe<\/code>i <code>select<\/code>z <code>@wordpress\/data<\/code>.<\/p>\n<pre><code>import { select, subscribe } from '@wordpress\/data';\n<\/code><\/pre>\n<p>Nast\u0119pnie u g\u00f3ry <code>componentDidMount<\/code>bloku kodu napisz:<\/p>\n<pre><code>subscribe(() =&gt; {\n  const { exampleText } = this.state;\n\n  const isSavingPost = select('core\/editor').isSavingPost();\n  const isAutosavingPost = select('core\/editor').isAutosavingPost();\n\n  if (isAutosavingPost) {\n    return;\n  }\n\n  if (! isSavingPost) {\n    return;\n  }\n\n  const settings = new api.models.Settings( {\n    [ 'wholesomecode_wholesome_plugin_example_text' ]: exampleText,\n  } );\n  settings.save();\n});\n<\/code><\/pre>\n<p>Kod wykonuje nast\u0119puj\u0105ce czynno\u015bci:<\/p>\n<ul>\n<li>Sprawdza, czy wpis si\u0119 zapisuje<\/li>\n<li>Sprawd\u017a, czy zapis jest zapisem automatycznym<\/li>\n<li>Je\u015bli wpis jest zapisywany i nie jest to autozapis, wepchnij nowe ustawienia do interfejsu Settings API<\/li>\n<li>Uruchom zapisywanie interfejsu Settings API.<\/li>\n<\/ul>\n<h3>Ma\u0142y hack<\/h3>\n<p>Mogliby\u015bmy tak zostawi\u0107 nasz kod, ale poniewa\u017c umieszczamy nasze ustawienia w bloku, a nie w pasku bocznym lub innym sk\u0142adniku edytora, je\u015bli zmienimy jedn\u0105 z opcji i nic innego w edytorze, przycisk \u201ezapisz&quot; nie uaktywnia\u0107 si\u0119.<\/p>\n<p>Dzieje si\u0119 tak, poniewa\u017c nie u\u017cywamy <code>setAttributes<\/code>ani niczego do zmiany rzeczywistego kodu bloku.<\/p>\n<p>Mo\u017cemy to obej\u015b\u0107, po prostu edytuj\u0105c inn\u0105 cz\u0119\u015b\u0107 posta lub dodaj\u0105c ma\u0142y hack do <code>TextControl<\/code>kodu:<\/p>\n<pre><code>onChange={ (exampleText) =&gt; { this.setState( { exampleText } ); setAttributes( { exampleText }) } }\n<\/code><\/pre>\n<p>Pami\u0119taj\u0105c o umieszczeniu tego wiersza kodu na pocz\u0105tku metody render w celu wyodr\u0119bnienia <code>setAttributes<\/code>z <code>props<\/code>(poniewa\u017c u\u017cywamy Component, uzyskujemy dost\u0119p do w\u0142a\u015bciwo\u015bci nieco innych z <code>this<\/code>.<\/p>\n<pre><code>const { setAttributes } = this.props;\n<\/code><\/pre>\n<p>Teraz, gdy zmienimy nasz atrybut, zmieni si\u0119 atrybut \u201efa\u0142szywy&#8221;, co sprawi, \u017ce redaktor pomy\u015bli, \u017ce mo\u017cemy teraz zapisa\u0107 post.<\/p>\n<p>To troch\u0119 dziwaczne, ale w tym przypadku u\u017cycia robi to, czego potrzebujemy.<\/p>\n<h3>Ca\u0142y <code>Edit<\/code>kod<\/h3>\n<p>Oto ca\u0142y kod potrzebny do <code>Edit<\/code>metody:<\/p>\n<p>importuj {} z &#8217; <a href=\"https:\/\/hashnode.com\/@wordpress\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">@wordpress<\/a> \/i18n&#8217;; importuj api z &#8217; <a href=\"https:\/\/hashnode.com\/@wordpress\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">@wordpress<\/a> \/api&#8217;; importuj { useBlockProps } z &#8217; <a href=\"https:\/\/hashnode.com\/@wordpress\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">@wordpress<\/a> \/block-editor&#8217;; importuj { Panel, PanelBody, Placeholder, Spinner, TextControl, } z &#8217; <a href=\"https:\/\/hashnode.com\/@wordpress\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">@wordpress<\/a> \/components&#8217;; importuj { wybierz, zasubskrybuj } z &#8217; <a href=\"https:\/\/hashnode.com\/@wordpress\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">@wordpress<\/a> \/data&#8217;; importuj { Komponent } z \u201e <a href=\"https:\/\/hashnode.com\/@wordpress\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">@wordpress<\/a> \/element&#8221;;<\/p>\n<p>import &#8217;.\/editor.scss&#8217;;<\/p>\n<p>class OptionsExample extends Sk\u0142adnik { konstruktor() { super( \u2026argumenty );<\/p>\n<pre><code>    this.state = {\n        exampleText: '',\n        isAPILoaded: false,\n    };\n}\n\ncomponentDidMount() {\n\n    subscribe( () =&gt; {\n        const { exampleText } = this.state;\n\n        const isSavingPost = select('core\/editor').isSavingPost();\n        const isAutosavingPost = select('core\/editor').isAutosavingPost();\n\n        if (isAutosavingPost) {\n            return;\n        }\n\n        if (! isSavingPost) {\n            return;\n        }\n\n        const settings = new api.models.Settings( {\n            [ 'wholesomecode_wholesome_plugin_example_text' ]: exampleText,\n        } );\n        settings.save();\n    });\n\n    api.loadPromise.then( () =&gt; {\n        this.settings = new api.models.Settings();\n\n        const { isAPILoaded } = this.state;\n\n        if (isAPILoaded === false) {\n            this.settings.fetch().then( (response) =&gt; {\n                this.setState( {\n                    exampleText: response[ 'wholesomecode_wholesome_plugin_example_text' ],\n                    isAPILoaded: true,\n                } );\n            } );\n        }\n    } );\n}\n\nrender() {\n    const {\n        exampleText,\n        isAPILoaded,\n    } = this.state;\n\n    const { setAttributes } = this.props;\n\n    if (! isAPILoaded) {\n        return (&lt;Placeholder&gt;\n                &lt;Spinner \/&gt;\n            &lt;\/Placeholder&gt;\n        );\n    }\n\n    return (&lt;Panel&gt;\n            &lt;PanelBody\n                title={ __( 'Example Meta Box', 'wholesomecode') }\n                icon=\"admin-plugins\"\n            &gt;\n                &lt;TextControl\n                    help={ __( 'This is an example text field.', 'wholesome-plugin') }\n                    label={ __( 'Example Text', 'wholesome-plugin') }\n                    onChange={ (exampleText) =&gt; { this.setState( { exampleText } ); setAttributes( { exampleText }) } }\n                    value={ exampleText }\n                \/&gt;\n            &lt;\/PanelBody&gt;\n        &lt;\/Panel&gt;) }\n<\/code><\/pre>\n<p>}<\/p>\n<p>eksportuj funkcj\u0119 domy\u015bln\u0105 Edit( props) { return (<\/p>\n<p>); }<\/p>\n<pre><code>\n### Remove the Attributes\n\nOption up `src\/index.js` and remove the attributes block that we placed there in the previous guides. We are not storing any attributes, the data will be pushed into and retrieved from the options table.\n\nRender the Output\n\nBecause we have saved our attribute as settings in the WordPress options table, we could output this anywhere in WordPress using `get_option`:\n<\/code><\/pre>\n<p>get_option( 'wholesomecode_wholesome_plugin_block_text&#8217;, &#8221; );<\/p>\n<pre><code>\nContinuing from the [Dynamic Block guide](https:\/\/wholesomecode.ltd\/guides\/php-render-block-wordpress-gutenberg\/), let's see how we can access this attribute on the server side in PHP.\n\nWith this in mind, let\u2019s update our `register_block_type` to output the option:\n<\/code><\/pre>\n<p>register_block_type( 'wholesomecode\/wholesome-plugin&#8217;, array( 'editor_script&#8217; =&gt; 'wholesomecode-wholesome-plugin-block-editor&#8217;, 'editor_style&#8217; =&gt; 'wholesomecode-wholesome-plugin-editor&#8217;, 'render_callback&#8217; = &gt; function( $attributes, $content) { $example_text = get_option( 'wholesomecode_wholesome_plugin_example_text&#8217; ); return &quot;<\/p>\n<p>$przyk\u0142ad_tekst<\/p>\n<p>&quot;; }, 'style&#8217; =&gt; 'wholesomecode-wholesome-plugin-block&#8217;,) );<\/p>\n<pre><code>\nNote that we no longer need to register the `attributes` here, because we are only accessing the post meta field via the `get_post_meta` function.\n\n5.  \nUsing the Block\n--------------------\n\nPutting it all together, let\u2019s see the block in action:\n\n![Using the block editor for settings and options](https:\n\nExtra: Add Some More Fields\n-----------------------------\n\nIn the extra steps of the Custom Meta Box guide, we added in some extra fields. Let\u2019s update the `Edit` method to include those same fields (note that I have omitted the hack):\n<\/code><\/pre>\n<p>import {} z &#8217; <a href=\"https:\/\/hashnode.com\/@wordpress\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">@wordpress<\/a> \/i18n&#8217;; importuj api z &#8217; <a href=\"https:\/\/hashnode.com\/@wordpress\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">@wordpress<\/a> \/api&#8217;; importuj { useBlockProps } z &#8217; <a href=\"https:\/\/hashnode.com\/@wordpress\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">@wordpress<\/a> \/block-editor&#8217;; importuj { Panel, PanelBody, PanelRow, Placeholder, SelectControl, Spinner, TextControl, ToggleControl, } z &#8217; <a href=\"https:\/\/hashnode.com\/@wordpress\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">@wordpress<\/a> \/components&#8217;; importuj { wybierz, zasubskrybuj } z &#8217; <a href=\"https:\/\/hashnode.com\/@wordpress\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">@wordpress<\/a> \/data&#8217;; importuj { Komponent } z \u201e <a href=\"https:\/\/hashnode.com\/@wordpress\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">@wordpress<\/a> \/element&#8221;;<\/p>\n<p>import &#8217;.\/editor.scss&#8217;;<\/p>\n<p>class OptionsExample extends Sk\u0142adnik { konstruktor() { super( \u2026argumenty );<\/p>\n<pre><code>    this.state = {\n        exampleSelect: '',\n        exampleText: '',\n        exampleText2: '',\n        exampleText3: '',\n        exampleToggle: false,\n        isAPILoaded: false,\n    };\n}\n\ncomponentDidMount() {\n\n    subscribe( () =&gt; {\n        const {\n            exampleSelect,\n            exampleText,\n            exampleText2,\n            exampleText3,\n            exampleToggle,\n        } = this.state;\n\n        const isSavingPost = select('core\/editor').isSavingPost();\n        const isAutosavingPost = select('core\/editor').isAutosavingPost();\n\n        if (isAutosavingPost) {\n            return;\n        }\n\n        if (! isSavingPost) {\n            return;\n        }\n\n        const settings = new api.models.Settings( {\n            [ 'wholesomecode_wholesome_plugin_example_select' ]: exampleSelect,\n            [ 'wholesomecode_wholesome_plugin_example_text' ]: exampleText,\n            [ 'wholesomecode_wholesome_plugin_example_text_2' ]: exampleText2,\n            [ 'wholesomecode_wholesome_plugin_example_text_3' ]: exampleText3,\n            [ 'wholesomecode_wholesome_plugin_example_toggle' ]: exampleToggle,\n        } );\n        settings.save();\n    });\n\n    api.loadPromise.then( () =&gt; {\n        this.settings = new api.models.Settings();\n\n        const { isAPILoaded } = this.state;\n\n        if (isAPILoaded === false) {\n            this.settings.fetch().then( (response) =&gt; {\n                this.setState( {\n                    exampleSelect: response[ 'wholesomecode_wholesome_plugin_example_select' ],\n                    exampleText: response[ 'wholesomecode_wholesome_plugin_example_text' ],\n                    exampleText2: response[ 'wholesomecode_wholesome_plugin_example_text_2' ],\n                    exampleText3: response[ 'wholesomecode_wholesome_plugin_example_text_3' ],\n                    exampleToggle: Boolean( response[ 'wholesomecode_wholesome_plugin_example_toggle' ] ),\n                    isAPILoaded: true,\n                } );\n            } );\n        }\n    } );\n}\n\nrender() {\n    const {\n        exampleSelect,\n        exampleText,\n        exampleText2,\n        exampleText3,\n        exampleToggle,\n        isAPILoaded,\n    } = this.state;\n\n    if (! isAPILoaded) {\n        return (&lt;Placeholder&gt;\n                &lt;Spinner \/&gt;\n            &lt;\/Placeholder&gt;\n        );\n    }\n\n    return (&lt;Panel&gt;\n            &lt;PanelBody\n                title={ __( 'Example Meta Box', 'wholesome-plugin') }\n                icon=\"admin-plugins\"\n            &gt;\n                &lt;SelectControl\n                    help={ __( 'An example dropdown field.', 'wholesome-plugin') }\n                    label={ __( 'Example Select', 'wholesome-plugin') }\n                    onChange={ (exampleSelect) =&gt; this.setState( { exampleSelect }) }\n                    options={ [\n                        {\n                            label: __( 'Please Select...', 'wholesome-plugin' ),\n                            value: '',\n                        },\n                        {\n                            label: __( 'Option 1', 'wholesome-plugin' ),\n                            value: 'option-1',\n                        },\n                        {\n                            label: __( 'Option 2', 'wholesome-plugin' ),\n                            value: 'option-2',\n                        },\n                    ] }\n                    value={ exampleSelect }\n                \/&gt;\n                &lt;TextControl\n                    help={ __( 'This is an example text field.', 'wholesome-plugin') }\n                    label={ __( 'Example Text', 'wholesome-plugin') }\n                    onChange={ (exampleText) =&gt; this.setState( { exampleText }) }\n                    value={ exampleText }\n                \/&gt;\n                &lt;PanelRow&gt;\n                    &lt;TextControl\n                        help={ __( 'Use PanelRow to place controls inline.', 'wholesome-plugin') }\n                        label={ __( 'Example Text 2', 'wholesome-plugin') }\n                        onChange={ (exampleText2) =&gt; this.setState( { exampleText2 }) }\n                        value={ exampleText2 }\n                    \/&gt;\n                    &lt;TextControl\n                        help={ __( 'This control is inline.', 'wholesome-plugin') }\n                        label={ __( 'Example Text 3', 'wholesome-plugin') }\n                        onChange={ (exampleText3) =&gt; this.setState( { exampleText3 }) }\n                        value={ exampleText3 }\n                    \/&gt;\n                &lt;\/PanelRow&gt;\n                &lt;ToggleControl\n                    checked={ exampleToggle }\n                    help={ __( 'An example toggle.', 'wholesome-plugin') }\n                    label={ __( 'Example Toggle', 'wholesome-plugin') }\n                    onChange={ (exampleToggle) =&gt; this.setState( { exampleToggle }) }\n                \/&gt;\n            &lt;\/PanelBody&gt;\n        &lt;\/Panel&gt;) }\n<\/code><\/pre>\n<p>}<\/p>\n<p>eksportuj funkcj\u0119 domy\u015bln\u0105 Edit( props) { return (<\/p>\n<p>); } `<\/p>\n<p>Oto wynik:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/wordpress.mediadoma.com\/wp-content\/uploads\/2022\/01\/post-169009-61e7fab7b579e.png\" alt=\"Korzystanie z opcji przechowywania danych w edytorze blok\u00f3w WordPress (Gutenberg)\" \/>Dodatkowe opcje<\/p>\n<ul>\n<li>Sp\u00f3jrz na tworzenie <a href=\"https:\/\/wholesomecode.ltd\/guides\/template-innerblocks-wordpress-gutenberg\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">zagnie\u017cd\u017conych blok\u00f3w podrz\u0119dnych za pomoc\u0105 <code>InnerBlocks<\/code>komponentu<\/a><\/li>\n<li>Zobacz, jak <a href=\"https:\/\/wholesomecode.ltd\/guides\/post-meta-fields-store-attributes-wordpress-gutenberg\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">u\u017cywa\u0107 meta p\u00f3l postu w blokach Gutenberga<\/a><\/li>\n<li>Sp\u00f3jrz na <a href=\"https:\/\/wholesomecode.ltd\/guides\/create-custom-meta-boxes-using-the-wordpress-block-editor-gutenberg\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">tworzenie niestandardowych skrzynek Meta w Gutenberg<\/a><\/li>\n<\/ul>\n<p><div id=\"PostUnique_PostSource\" style=\"padding-top: 50px\">\u0179r\u00f3d\u0142o nagrywania:  <a target=\"_blank\" rel=\"noopener nofollow\" href=\"\/\/wholesomecode.ltd\" class=\"external external_icon\">wholesomecode.ltd<\/a><\/div><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Wcze\u015bniej badali\u015bmy przechowywanie danych edytora blok\u00f3w WordPress (Gutenberg) w atrybutach blok\u00f3w i meta postu, ale czy wiesz, \u017ce mo\u017cesz przechowywa\u0107 i pobiera\u0107 z WordPressa &#8230;<\/p>\n","protected":false},"author":1,"featured_media":223685,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","_wp_rev_ctl_limit":""},"categories":[721,940,897,805,845,866],"tags":[1169],"class_list":["post-228206","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-deweloper","category-gutenberg-7","category-kod","category-php-7","category-samouczki","category-wordpress-7","tag-affiai-pl"],"_links":{"self":[{"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/posts\/228206","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=228206"}],"version-history":[{"count":0,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/posts\/228206\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/media\/223685"}],"wp:attachment":[{"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/media?parent=228206"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/categories?post=228206"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/tags?post=228206"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}