{"id":228314,"date":"2022-10-16T15:24:00","date_gmt":"2022-10-16T12:24:00","guid":{"rendered":"https:\/\/wordpress.mediadoma.com\/?p=228314"},"modified":"2022-11-09T01:49:58","modified_gmt":"2022-11-08T22:49:58","slug":"uso-de-opciones-para-almacenar-datos-en-el-editor-de-bloques-de-wordpress-gutenberg","status":"publish","type":"post","link":"https:\/\/wordpress.mediadoma.com\/es\/uso-de-opciones-para-almacenar-datos-en-el-editor-de-bloques-de-wordpress-gutenberg\/","title":{"rendered":"Uso de opciones para almacenar datos en el editor de bloques de WordPress (Gutenberg)"},"content":{"rendered":"\n<p>Anteriormente exploramos el almacenamiento de datos del editor de bloques de WordPress (Gutenberg) en los <a href=\"https:\/\/wholesomecode.ltd\/guides\/creating-plugin-wordpress-gutenberg\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">atributos de bloque<\/a> y en <a href=\"https:\/\/wholesomecode.ltd\/guides\/post-meta-fields-store-attributes-wordpress-gutenberg\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">la publicaci\u00f3n meta<\/a>, pero \u00bfsab\u00eda que puede almacenar y recuperar desde la tabla de opciones de WordPress importando <code>api<\/code>desde <code>@wordpress\/api<\/code>.<\/p>\n<p>En esta gu\u00eda, echamos un vistazo a lo que escribir\u00edas cl\u00e1sicamente en PHP como <code>update_option<\/code>y <code>get_option<\/code>.<\/p>\n<p>Para implementar esto, debemos aprovechar el ciclo de vida de React, por lo que veremos c\u00f3mo crear un componente de React importando <code>Component<\/code>desde <code>@wordpress\/element<\/code>.<\/p>\n<h2>requisitos previos<\/h2>\n<ul>\n<li>Familiar\u00edcese con <a href=\"https:\/\/wholesomecode.ltd\/guides\/creating-plugin-wordpress-gutenberg\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">la creaci\u00f3n de complementos para WordPress Gutenberg<\/a><\/li>\n<li>Sea familiar <a href=\"https:\/\/wholesomecode.ltd\/guides\/php-render-block-wordpress-gutenberg\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">con los bloques din\u00e1micos y la representaci\u00f3n del lado del servidor<\/a><\/li>\n<li>Comprenda c\u00f3mo puede <a href=\"https:\/\/wholesomecode.ltd\/guides\/custom-meta-boxes-wordpress-gutenberg\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">crear metaboxes en Gutenberg<\/a><\/li>\n<\/ul>\n<p>Ese \u00faltimo requisito es \u00fatil para la interfaz de usuario que vamos a usar en esta gu\u00eda; sin embargo, en aplicaciones del mundo real, es probable que use este m\u00e9todo en una barra lateral o en una p\u00e1gina de opciones.<\/p>\n<h2>Registrar las Opciones en PHP<\/h2>\n<p>Antes de que podamos usar una opci\u00f3n en JavaScript, debemos asegurarnos de que la hayamos registrado en PHP usando <code>register_setting<\/code>y que el <code>show_in_rest<\/code>argumento se haya establecido en verdadero.<\/p>\n<p>Siguiendo con la <a href=\"https:\/\/wholesomecode.ltd\/guides\/php-render-block-wordpress-gutenberg\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">gu\u00eda de Dynamic Block<\/a>, abra el archivo PHP ra\u00edz del complemento (en este caso <code>wholesome-plugin.php<\/code>) y agregue el siguiente c\u00f3digo al final de ese archivo despu\u00e9s de todas las dem\u00e1s funciones:<\/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>Este c\u00f3digo registra un metacampo llamado <code>wholesomecode_wholesome_plugin_block_text<\/code>para el <code>wholesomecode_wholesome_plugin_settings<\/code>grupo de opciones. Tambi\u00e9n garantiza que la API REST pueda acceder a este metacampo con el <code>show_in_rest<\/code>valor establecido en verdadero.<\/p>\n<h2>Crear el componente<\/h2>\n<p>Abra el <code>\/src\/edit.js<\/code>archivo, vamos a alterar un poco la estructura de este archivo para que podamos generar nuestro archivo <code>Component<\/code>.<\/p>\n<p>Corte y pegue la totalidad de este bloque de c\u00f3digo en el <code>\/src\/edit.js<\/code>archivo, cubriremos lo que hace en un momento:<\/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>Puede reconocer que la interfaz de usuario que hemos implementado es exactamente la misma de la gu\u00eda <a href=\"https:\/\/wholesomecode.ltd\/guides\/custom-meta-boxes-wordpress-gutenberg\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">Gutenberg Meta Box<\/a>, donde usamos meta atributos de publicaci\u00f3n. Tambi\u00e9n puede notar que todav\u00eda no estamos obteniendo o configurando informaci\u00f3n usando opciones, y en su lugar solo estamos usando el componente <code>state<\/code>.<\/p>\n<h3>Estado de uso<\/h3>\n<p>La raz\u00f3n por la que creamos un componente personalizado y luego lo pasamos a nuestra <code>Edit<\/code>funci\u00f3n es para que podamos aprovechar el estado. Hemos hecho esto porque:<\/p>\n<ul>\n<li>Crearemos una funci\u00f3n para cargar las opciones de la API, y debemos almacenar esto en el estado para que nuestros componentes puedan leerlo.<\/li>\n<li>No queremos que la API actualice las opciones tan pronto como cambie el texto en nuestro cuadro de texto, por lo que necesitamos una funci\u00f3n para guardar el estado en las opciones a trav\u00e9s de la API una vez que se haya guardado la publicaci\u00f3n.<\/li>\n<\/ul>\n<p>Usar el estado es bastante simple. En el constructor inicializamos el estado as\u00ed:<\/p>\n<pre><code>this.state = { exampleText: '' };\n<\/code><\/pre>\n<p>Y en el componente accedemos a \u00e9l de forma similar a como hemos accedido a los atributos en la gu\u00eda anterior:<\/p>\n<pre><code>const { exampleText } = this.state;\n<\/code><\/pre>\n<p>La diferencia es que, en nuestro <code>onChange<\/code>m\u00e9todo, en lugar de usar <code>setAttributes<\/code>, usamos <code>this.setState<\/code>.<\/p>\n<h3>Obtener opciones de la API<\/h3>\n<p>En la parte superior del documento importar <code>api<\/code>desde <code>@wordpress\/api<\/code>:<\/p>\n<pre><code>import api from '@wordpress\/api';\n<\/code><\/pre>\n<p>Agregue una nueva propiedad donde se inicializa el estado de <code>isAPILoaded<\/code>. Necesitaremos esto para asegurarnos de que no intentamos acceder a la API o renderizar el componente antes de que se haya cargado la API.<\/p>\n<pre><code>this.state = {\n  exampleText: '',\n  isAPILoaded: false,\n};\n<\/code><\/pre>\n<p>Ahora dentro del Componente que creamos, agregue un bloque de c\u00f3digo bajo el constructor llamado <code>componentDidMount<\/code>. Este es un m\u00e9todo de ciclo de vida de React, que se llama despu\u00e9s de que se ha agregado un componente al DOM.<\/p>\n<p>En ese bloque de c\u00f3digo agregue lo siguiente:<\/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>Aqu\u00ed estamos accediendo a la opci\u00f3n que registramos anteriormente con la <code>register_setting<\/code>funci\u00f3n.<\/p>\n<p>Este bloque de c\u00f3digo hace lo siguiente:<\/p>\n<ul>\n<li>Obtiene la configuraci\u00f3n de la API de configuraci\u00f3n de Guttenberg de WordPress.<\/li>\n<li>Obtiene <code>isAPILoaded<\/code>del estado<\/li>\n<li>Si la API no se ha cargado, obtiene la configuraci\u00f3n de la API en un<code>response<\/code><\/li>\n<li>Luego configuramos el estado para actualizar el estado con la opci\u00f3n a la que queremos acceder y establecemos el <code>isAPILoaded<\/code>estado en verdadero<\/li>\n<\/ul>\n<h3>Detener la representaci\u00f3n de bloques sin configuraci\u00f3n<\/h3>\n<p>No queremos que nuestro bloque se represente antes de que se hayan completado las configuraciones. Para encargarnos de esto, podemos importar un PlaceHolder y un Spinner desde <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>Luego, en el m\u00e9todo de representaci\u00f3n del componente, aseg\u00farese de obtener <code>isAPILoaded<\/code>del estado y genere el <code>Placeholder<\/code>y <code>Spinner<\/code>si no es as\u00ed:<\/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>De esta forma, si las opciones no se han cargado, obtenemos un bonito marcador de posici\u00f3n hasta que se carga el componente:<\/p>\n<p>Marcador de posici\u00f3n y Spinner<\/p>\n<h3>Conexi\u00f3n con Gutenberg en Save<\/h3>\n<p>Ahora que estamos leyendo las opciones de la tabla de opciones, necesitamos una forma de guardar esas opciones cuando las cambiamos. Para ello vamos al <code>subscribe<\/code>almac\u00e9n de datos de WordPress Gutenberg, que nos indicar\u00e1 cuando algo haya cambiado.<\/p>\n<p>Al usar esto, crearemos un oyente para cuando se guarde la publicaci\u00f3n y guardaremos nuestra configuraci\u00f3n cuando eso suceda.<\/p>\n<p>Para ello importa <code>subscribe<\/code>y <code>select<\/code>desde <code>@wordpress\/data<\/code>.<\/p>\n<pre><code>import { select, subscribe } from '@wordpress\/data';\n<\/code><\/pre>\n<p>Luego, en la parte superior del <code>componentDidMount<\/code>bloque de c\u00f3digo, escribe lo siguiente:<\/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>El c\u00f3digo hace lo siguiente:<\/p>\n<ul>\n<li>Comprueba si la publicaci\u00f3n se est\u00e1 guardando<\/li>\n<li>Verifique si el guardado es un guardado autom\u00e1tico<\/li>\n<li>Si la publicaci\u00f3n se est\u00e1 guardando y no se guarda autom\u00e1ticamente, inserte la nueva configuraci\u00f3n en la API de configuraci\u00f3n<\/li>\n<li>Active un guardado de la API de configuraci\u00f3n.<\/li>\n<\/ul>\n<h3>Un peque\u00f1o truco<\/h3>\n<p>Podr\u00edamos dejar nuestro c\u00f3digo as\u00ed, pero debido a que estamos colocando nuestra configuraci\u00f3n en un bloque, y no en una barra lateral u otro componente del editor, si cambiamos una de las opciones, y nada m\u00e1s en el editor, el bot\u00f3n &#8216;guardar&#8217; no volverse activo.<\/p>\n<p>Esto se debe a que no estamos usando <code>setAttributes<\/code>ni nada para alterar el c\u00f3digo real del bloque.<\/p>\n<p>Podemos solucionar esto simplemente editando otra parte de la publicaci\u00f3n o agregando un peque\u00f1o truco en el <code>TextControl<\/code>c\u00f3digo:<\/p>\n<pre><code>onChange={ (exampleText) =&gt; { this.setState( { exampleText } ); setAttributes( { exampleText }) } }\n<\/code><\/pre>\n<p>Recordando poner esta l\u00ednea de c\u00f3digo en la parte superior del m\u00e9todo de renderizado para extraer <code>setAttributes<\/code>del <code>props<\/code>(debido a que estamos usando un Componente, accedemos a los accesorios ligeramente diferentes con <code>this<\/code>.<\/p>\n<pre><code>const { setAttributes } = this.props;\n<\/code><\/pre>\n<p>Ahora, cuando cambiamos nuestro atributo, un atributo &#8216;falso&#8217; cambiar\u00e1, lo que har\u00e1 que el editor piense que ahora podemos guardar la publicaci\u00f3n.<\/p>\n<p>Es un poco raro, pero para este caso de uso hace lo que necesitamos.<\/p>\n<h3><code>Edit<\/code>El c\u00f3digo completo<\/h3>\n<p>Aqu\u00ed est\u00e1 todo el c\u00f3digo que necesita para el <code>Edit<\/code>m\u00e9todo:<\/p>\n<p>yo ` import {} de &#8216; <a href=\"https:\/\/hashnode.com\/@wordpress\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">@wordpress<\/a> \/i18n&#8217;; importar api desde &#8216; <a href=\"https:\/\/hashnode.com\/@wordpress\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">@wordpress<\/a> \/api&#8217;; importar { useBlockProps } desde &#8216; <a href=\"https:\/\/hashnode.com\/@wordpress\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">@wordpress<\/a> \/block-editor&#8217;; import { Panel, PanelBody, Placeholder, Spinner, TextControl, } from &#8216; <a href=\"https:\/\/hashnode.com\/@wordpress\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">@wordpress<\/a> \/components&#8217;; importar { seleccionar, suscribirse } desde &#8216; <a href=\"https:\/\/hashnode.com\/@wordpress\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">@wordpress<\/a> \/data&#8217;; importar {Componente} desde &#8216; <a href=\"https:\/\/hashnode.com\/@wordpress\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">@wordpress<\/a> \/element&#8217;;<\/p>\n<p>importar &#8216;.\/editor.scss&#8217;;<\/p>\n<p>clase OpcionesEjemplo extiende Componente { constructor() { super( \u2026argumentos );<\/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>Exportar funci\u00f3n predeterminada Editar (accesorios) { volver (<\/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(&#8216;wholesomecode_wholesome_plugin_block_text&#8217;, &quot; );<\/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( &#8216;wholesomecode\/wholesome-plugin&#8217;, array( &#8216;editor_script&#8217; =&gt; &#8216;wholesomecode-wholesome-plugin-block-editor&#8217;, &#8216;editor_style&#8217; =&gt; &#8216;wholesomecode-wholesome-plugin-block-editor&#8217;, &#8216;render_callback&#8217; = &gt; function ($atributos, $contenido) { $example_text = get_option( &#8216;wholesomecode_wholesome_plugin_example_text&#8217; ); return &quot;<\/p>\n<p>$ejemplo_texto<\/p>\n<p>&quot;; }, &#8216;style&#8217; =&gt; &#8216;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>importar {} de &#8216; <a href=\"https:\/\/hashnode.com\/@wordpress\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">@wordpress<\/a> \/i18n&#8217;; importar api desde &#8216; <a href=\"https:\/\/hashnode.com\/@wordpress\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">@wordpress<\/a> \/api&#8217;; importar { useBlockProps } desde &#8216; <a href=\"https:\/\/hashnode.com\/@wordpress\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">@wordpress<\/a> \/block-editor&#8217;; import { Panel, PanelBody, PanelRow, Placeholder, SelectControl, Spinner, TextControl, ToggleControl, } from &#8216; <a href=\"https:\/\/hashnode.com\/@wordpress\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">@wordpress<\/a> \/components&#8217;; importar { seleccionar, suscribirse } desde &#8216; <a href=\"https:\/\/hashnode.com\/@wordpress\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">@wordpress<\/a> \/data&#8217;; importar {Componente} desde &#8216; <a href=\"https:\/\/hashnode.com\/@wordpress\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">@wordpress<\/a> \/element&#8217;;<\/p>\n<p>importar &#8216;.\/editor.scss&#8217;;<\/p>\n<p>clase OpcionesEjemplo extiende Componente { constructor() { super( \u2026argumentos );<\/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>Exportar funci\u00f3n predeterminada Editar (accesorios) { volver (<\/p>\n<p>); } `<\/p>\n<p>Aqu\u00ed est\u00e1 el resultado:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/wordpress.mediadoma.com\/wp-content\/uploads\/2022\/01\/post-169009-61e7fab7b579e.png\" alt=\"Uso de opciones para almacenar datos en el editor de bloques de WordPress (Gutenberg)\" \/>Opciones adicionales<\/p>\n<ul>\n<li>Eche un vistazo a la creaci\u00f3n de <a href=\"https:\/\/wholesomecode.ltd\/guides\/template-innerblocks-wordpress-gutenberg\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">bloques secundarios anidados con el <code>InnerBlocks<\/code>componente<\/a><\/li>\n<li>Eche un vistazo al <a href=\"https:\/\/wholesomecode.ltd\/guides\/post-meta-fields-store-attributes-wordpress-gutenberg\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">uso de metacampos de publicaci\u00f3n en bloques de Gutenberg<\/a><\/li>\n<li>Eche un vistazo a la <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\">creaci\u00f3n de metaboxes personalizados en Gutenberg<\/a><\/li>\n<\/ul>\n<p><div id=\"PostUnique_PostSource\" style=\"padding-top: 50px\">Fuente de grabaci\u00f3n:  <a target=\"_blank\" rel=\"noopener nofollow\" href=\"\/\/wholesomecode.ltd\" class=\"external external_icon\">wholesomecode.ltd<\/a><\/div><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Anteriormente, exploramos el almacenamiento de datos del editor de bloques de WordPress (Gutenberg) en atributos de bloque y en metadatos de publicaci\u00f3n, pero \u00bfsab\u00eda que puede almacenar y recuperar en el WordPress&#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":[892,716,935,800,840,861],"tags":[1172],"class_list":["post-228314","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-codigo","category-desarrollador","category-gutenberg-2","category-php-2","category-tutoriales","category-wordpress-2","tag-affiai-es"],"_links":{"self":[{"href":"https:\/\/wordpress.mediadoma.com\/es\/wp-json\/wp\/v2\/posts\/228314","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.mediadoma.com\/es\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wordpress.mediadoma.com\/es\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/es\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/es\/wp-json\/wp\/v2\/comments?post=228314"}],"version-history":[{"count":0,"href":"https:\/\/wordpress.mediadoma.com\/es\/wp-json\/wp\/v2\/posts\/228314\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/es\/wp-json\/wp\/v2\/media\/223685"}],"wp:attachment":[{"href":"https:\/\/wordpress.mediadoma.com\/es\/wp-json\/wp\/v2\/media?parent=228314"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/es\/wp-json\/wp\/v2\/categories?post=228314"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/es\/wp-json\/wp\/v2\/tags?post=228314"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}