{"id":228397,"date":"2022-10-18T11:46:00","date_gmt":"2022-10-18T08:46:00","guid":{"rendered":"https:\/\/wordpress.mediadoma.com\/?p=228397"},"modified":"2022-11-09T02:14:42","modified_gmt":"2022-11-08T23:14:42","slug":"uso-del-editor-de-bloques-de-wordpress-gutenberg-con-la-api-rest","status":"publish","type":"post","link":"https:\/\/wordpress.mediadoma.com\/es\/uso-del-editor-de-bloques-de-wordpress-gutenberg-con-la-api-rest\/","title":{"rendered":"Uso del editor de bloques de WordPress (Gutenberg) con la API REST"},"content":{"rendered":"\n<p>En mi art\u00edculo anterior, habl\u00e9 sobre <a href=\"https:\/\/wholesomecode.ltd\/articles\/wp_query-and-the-wordpress-block-editor-gutenberg\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">c\u00f3mo recorrer publicaciones y tipos de publicaciones personalizadas dentro de Gutenberg<\/a>. En esta publicaci\u00f3n, hablo sobre la recepci\u00f3n y el uso de datos personalizados dentro de Gutenberg desde los puntos finales de la API REST de WordPress.<\/p>\n<p>En este ejemplo vamos a:<\/p>\n<p><strong>La API REST no siempre es el camino correcto.<\/strong><\/p>\n<p>*Usamos <code>get_option<\/code>en la API REST solo como ejemplo. Si solo necesita acceso a una opci\u00f3n y no tiene la intenci\u00f3n de cambiar su estado, puede usar <code>wp_localize_script<\/code>para pasar las opciones a JavaScript.<\/p>\n<p>Si desea acceder a una opci\u00f3n Y cambiar su estado, le recomendar\u00eda leer mi <a href=\"https:\/\/wholesomecode.ltd\/guides\/options-settings-data-wordpress-gutenberg\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">gu\u00eda sobre el almacenamiento de configuraciones y datos en la tabla de opciones con Gutenberg usando la API de configuraci\u00f3n<\/a> .*<\/p>\n<h2>Creaci\u00f3n de un punto final de API REST<\/h2>\n<p>Vamos a crear un punto final de API REST simple que devuelva el valor de una opci\u00f3n de WordPress (usando <code>get_option<\/code>).<\/p>\n<pre><code>function wcltd_get_option() {\n    register_rest_route(\n        'wcltd\/wholesome-plugin\/v1',\n        '\/get\/option\/(?P&lt;option&gt;([A-Za-z0-9_])+)\/',\n        array(\n            'callback'            =&gt; function ($request) {\n                $option = isset( $request['option'] )? esc_attr( $request['option'] ): null;\n                $value  = get_option( $option, '' );\n                return $value;\n            },\n            'methods'             =&gt; 'GET',) );\n}\nadd_action( 'rest_api_init', 'wcltd_get_option' );\n<\/code><\/pre>\n<p>Despu\u00e9s de haber creado este punto final, aseg\u00farese de volver a <strong>guardar sus enlaces permanentes<\/strong> para que se active. Tenga en cuenta que hay mejores formas de hacer esto (como usar <code>flush_rewrite_rules()<\/code>en el <code>register_activation_hook<\/code>), pero para este ejemplo, bastar\u00e1 con volver a guardar r\u00e1pidamente.<\/p>\n<p>Ahora, cuando pasemos la URL <code>\/wp-json\/wcltd\/wholesome-plugin\/v1\/get\/option\/test\/<\/code>(despu\u00e9s de su propio dominio, obviamente) a nuestro navegador, devolver\u00e1 un valor, que puede ser una cadena vac\u00eda <code>''<\/code>o el valor de la opci\u00f3n si est\u00e1 configurada.<\/p>\n<p><a href=\"https:\/\/cdn.hashnode.com\/res\/hashnode\/image\/upload\/v1639990082853\/S6umfXuzNF.png\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">Nuestro punto final, devolviendo una cadena vac\u00eda<\/a> Nuestro punto final, devolviendo una cadena vac\u00eda<\/p>\n<p>Tenga en cuenta que he comentado a prop\u00f3sito las l\u00edneas 12-14, lo que garantizar\u00eda que solo alguien que tenga <code>edit_post<\/code>derechos pueda ejecutar el c\u00f3digo si se deja. Sin embargo, con esto comentado, no podemos probar el c\u00f3digo en nuestro navegador.<\/p>\n<p>Intente agregar alg\u00fan c\u00f3digo para darle un valor a su opci\u00f3n y vea qu\u00e9 devuelve. Por ejemplo, si tuviera que ejecutar el siguiente c\u00f3digo antes de mi funci\u00f3n:<\/p>\n<pre><code>update_option( 'wcltd_example_option', 'Hello World' );\n<\/code><\/pre>\n<p>Ahora, si llego al punto final <code>\/wp-json\/wcltd\/wholesome-plugin\/v1\/get\/option\/wcltd_example_option\/<\/code>, obtendr\u00e9 el siguiente resultado:<\/p>\n<p>Nuestro punto final, devolviendo algunos datos.<\/p>\n<h2>Registro de un almac\u00e9n de datos<\/h2>\n<p>Ahora que tenemos un punto final de API REST, podemos crear un almac\u00e9n de datos con <code>registerStore<\/code>.<\/p>\n<p><code>registerStore<\/code>proporciona un almac\u00e9n de datos similar a Redux, que nos permite administrar el estado en toda nuestra aplicaci\u00f3n. Tambi\u00e9n es compatible con los resolutores, que nos permiten completar el estado desde una fuente externa (como nuestra API REST).<\/p>\n<p>Puede <a href=\"https:\/\/reactjs.org\/docs\/state-and-lifecycle.html\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">leer m\u00e1s sobre el estado REACT en la documentaci\u00f3n oficial<\/a>.<\/p>\n<p>As\u00ed es como podemos crear una tienda (como <code>store.js<\/code>en nuestro proyecto que nos permitir\u00e1 extraer datos de nuestro punto final de API REST.<\/p>\n<h3>dependencias<\/h3>\n<p>Tendremos que extraer <code>apiFetch<\/code>y <code>registerStore<\/code>de nuestras dependencias de WordPress.<\/p>\n<pre><code>import apiFetch from '@wordpress\/api-fetch';\nimport { registerStore } from '@wordpress\/data';\n<\/code><\/pre>\n<h3>Selectores<\/h3>\n<p>Lo primero que queremos hacer es crear una funci\u00f3n selectora, en un objeto llamado &#8216;selectores&#8217;.<\/p>\n<p>Todo lo que hace es extraer la &#8216;opci\u00f3n&#8217; del estado y devolverla.<\/p>\n<pre><code>const selectors = {\n    getOption( state, optionKey) {\n        const { option } = state;\n        return option;\n    },\n};\n<\/code><\/pre>\n<h3>Resolutores<\/h3>\n<p>El resolver es un efecto secundario del selector y hace un poco m\u00e1s.<\/p>\n<p>Aqu\u00ed creamos nuestra funci\u00f3n que toma nuestra optionKey y pasa un punto final de API REST a nuestras acciones (que definiremos a continuaci\u00f3n).<\/p>\n<p>Esto luego establece la opci\u00f3n, con otra llamada a nuestras acciones.<\/p>\n<pre><code>const resolvers = {\n    *getOption( optionKey) {\n        const option = yield actions.getOption(\n            '\/wcltd\/wholesome-plugin\/v1\/get\/option\/' + optionKey + '\/',\n        );\n        return actions.setOption( option );\n    },\n};\n<\/code><\/pre>\n<h3>Comportamiento<\/h3>\n<p>Las dos funciones en un objeto llamado <code>actions<\/code>que llamamos anteriormente se definen aqu\u00ed.<\/p>\n<p>Indican qu\u00e9 control o reductor vamos a utilizar para fijar u obtener el valor.<\/p>\n<pre><code>const actions = {\n    setOption( option) {\n        return {\n            type: 'SET_OPTION',\n            option,\n        };\n    },\n    getOption( path) {\n        return {\n            type: 'GET_OPTION',\n            path,\n        };\n    },\n};\n<\/code><\/pre>\n<h3>Control S<\/h3>\n<p>En nuestros controles tenemos <code>GET_OPTION<\/code>que hace la llamada a la API usando <code>apiFetch<\/code>y la ruta que definimos anteriormente.<\/p>\n<pre><code>const controls = {\n    GET_OPTION( action) {\n        return apiFetch( { path: action.path } );\n    },\n};\n<\/code><\/pre>\n<h3>reductor<\/h3>\n<p>En nuestra funci\u00f3n reductora tenemos <code>SET_OPTION<\/code>que toma nuestro valor (en este caso <code>option<\/code>, y establece su estado.<\/p>\n<pre><code>function reducer( state = { option: '' }, action) {\n    switch (action.type) {\n        case 'SET_OPTION':\n            return {\n                ...state,\n                option: action.option,\n            };\n    }\n    return state;\n};\n<\/code><\/pre>\n<h3>Registro de la tienda<\/h3>\n<p>Finalmente, registramos una tienda, le damos un espacio de nombres para que podamos acceder a ella y pasamos un objeto de todos los objetos y funciones anteriores.<\/p>\n<pre><code>const store = registerStore(\n    'wcltd\/wholesome-plugin\/data',\n    {\n        actions,\n        controls,\n        reducer,\n        resolvers,\n        selectors,\n    }\n);\n\nexport default store;\n<\/code><\/pre>\n<p>exportar almac\u00e9n predeterminado;<\/p>\n<h2>Usando los datos con un bloque<\/h2>\n<p>Expandamos el <a href=\"https:\/\/wholesomecode.ltd\/articles\/an-overview-of-the-wordpress-create-block-script\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">bloque creado por el <code>@wordpress\/create-block<\/code>script, sobre el que escrib\u00ed anteriormente<\/a> para permitirnos conectarnos a un punto final de API REST.<\/p>\n<p>Cree un archivo en la <code>\/src<\/code>carpeta llamada <code>store.js<\/code>y copie todo el c\u00f3digo anterior en \u00e9l:<\/p>\n<pre><code>import apiFetch from '@wordpress\/api-fetch';\nimport { registerStore } from '@wordpress\/data';\n\nconst selectors = {\n    getOption( state, optionKey) {\n        const { option } = state;\n        return option;\n    },\n};\n\nconst resolvers = {\n    *getOption( optionKey) {\n        const option = yield actions.getOption(\n            '\/wcltd\/wholesome-plugin\/v1\/get\/option\/' + optionKey + '\/',\n        );\n        return actions.setOption( option );\n    },\n};\n\nconst actions = {\n    setOption( option) {\n        return {\n            type: 'SET_OPTION',\n            option,\n        };\n    },\n    getOption( path) {\n        return {\n            type: 'GET_OPTION',\n            path,\n        };\n    },\n};\n\nconst controls = {\n    GET_OPTION( action) {\n        return apiFetch( { path: action.path } );\n    },\n};\n\nfunction reducer( state = { option: '' }, action) {\n    switch (action.type) {\n        case 'SET_OPTION':\n            return {\n                ...state,\n                option: action.option,\n            };\n    }\n    return state;\n};\n\nconst store = registerStore(\n    'wcltd\/wholesome-plugin\/data',\n    {\n        actions,\n        controls,\n        reducer,\n        resolvers,\n        selectors,\n    }\n);\n\nexport default store;\n<\/code><\/pre>\n<p>Ahora edite nuestro <code>\/src\/index.js<\/code>archivo para incluir el <code>store.js<\/code>archivo:<\/p>\n<pre><code>\nimport store from '.\/store';\nimport Edit from '.\/edit';\nimport save from '.\/save';\n<\/code><\/pre>\n<p>Tambi\u00e9n debemos asegurarnos de haber incluido <code>withSelect<\/code>en la parte superior de nuestro archivo:<\/p>\n<pre><code>import { withSelect } from '@wordpress\/data';\n<\/code><\/pre>\n<p>Luego, envolvamos nuestro m\u00f3dulo Edit con <code>withSelect<\/code>para hacer que la API REST llame a nuestra opci\u00f3n, as\u00ed:<\/p>\n<pre><code>\nedit: withSelect( (select) =&gt; {\n    const option = select( 'wcltd\/wholesome-plugin\/data' ).getOption( 'wcltd_example_option' );\n    return {\n        option,\n    };\n} )( Edit ),\n<\/code><\/pre>\n<p>Ahora podemos acceder <code>option<\/code>a nuestros accesorios dentro <code>edit.js<\/code>de, as\u00ed:<\/p>\n<pre><code>export default function Edit( { className, option }) {\n    return (&lt;p className={ className }&gt;\n            { option }\n        &lt;\/p&gt;\n    );\n}\n<\/code><\/pre>\n<p>Finalmente, veamos nuestro bloque en el editor y veamos qu\u00e9 obtenemos:<\/p>\n<p><a href=\"https:\/\/cdn.hashnode.com\/res\/hashnode\/image\/upload\/v1639990090843\/2uT6sdoTo.png\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">La salida en el editor de bloques.<\/a> La salida en el editor de bloques.<\/p>\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>En mi art\u00edculo anterior, habl\u00e9 sobre c\u00f3mo recorrer publicaciones y tipos de publicaciones personalizadas dentro de Gutenberg. En esta publicaci\u00f3n, hablo sobre la recepci\u00f3n y el uso de datos personalizados dentro de Gutenberg f&#8230;<\/p>\n","protected":false},"author":1,"featured_media":220671,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","_wp_rev_ctl_limit":""},"categories":[892,716,914,861],"tags":[1172],"class_list":["post-228397","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-codigo","category-desarrollador","category-otro","category-wordpress-2","tag-affiai-es"],"_links":{"self":[{"href":"https:\/\/wordpress.mediadoma.com\/es\/wp-json\/wp\/v2\/posts\/228397","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=228397"}],"version-history":[{"count":0,"href":"https:\/\/wordpress.mediadoma.com\/es\/wp-json\/wp\/v2\/posts\/228397\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/es\/wp-json\/wp\/v2\/media\/220671"}],"wp:attachment":[{"href":"https:\/\/wordpress.mediadoma.com\/es\/wp-json\/wp\/v2\/media?parent=228397"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/es\/wp-json\/wp\/v2\/categories?post=228397"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/es\/wp-json\/wp\/v2\/tags?post=228397"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}