POZOR! Článek jsem napsal před více jak rokem, a tudíž už nemusí reflektovat můj nynější názor nebo může být zastaralý.
V minulém článku jsem ukázal, jak tvořit jednoduchý Gutenberg blok a v tomto příspěvku vytvořím nový blok, který napojím na data z WordPress Rest API. Ukážu to na jednoduchém příkladu, ve kterém si do mého Gutenberg bloku („Autoři článku“) budu natahovat data o uživatelích WordPressu.
- Vytvořím WordPress Rest API endpoint
- Vytvořím samotný Gutenberg blok s napojením na API
- Ukážu jak data využít při renderování bloku
- Ukážu jak blok následně reálně vypadá
Vytvoření WordPress Rest API endpointu
Vytvořím si jednoduchou třídu, která zaregistruje jediný API endpoint, který bude vracet uživatele:
/wp-content/plugins/katuscak-gutenberg/inc/API.class.php
<?php
namespace KatuscakGutenberg;
class API
{
private $namespace;
public function __construct()
{
$this->namespace = 'katuscak-gutenberg';
}
public function init()
{
add_action('rest_api_init', function () {
register_rest_route(
$this->namespace,
'/users',
[
'methods' => 'GET',
'callback' => [$this, 'getUsers'],
]
);
});
}
public function getUsers()
{
$users = [];
$result = get_users(['fields' => ['display_name', "ID"]]);
foreach ($result as $user) {
$users[] = [
'value' => $user->ID,
'label' => $user->display_name,
];
}
return $users;
}
}
Nesmím zapomenout jej také v pluginu inicializovat:
/wp-content/plugins/katuscak-gutenberg/katuscak-gutenberg.php
<?php
/*
Plugin Name: Katuscak Gutenberg Blocks
Description: Gutenberg plugin with awesome blocks
Author: Michal Katuščák
Version: 0.1
Author URI: https://www.katuscak.cz/
*/
include_once __DIR__ . "/inc/API.class.php";
$api = new \KatuscakGutenberg\API();
$api->init();
// ... další kód
Vytvoření Gutenberg bloku s napojení na API
Oproti předchozí ukázce bude blok o něco složitější. Zde už využiji npm balíček @wordpress/data, který je podobný React Reduxu (rozdíly jsou popsané v dokumentaci WordPressu, ale vesměs používá stejnou terminologii a principy), který se postará o management dat (v tomto případě o seznam uživatelů). Pro ty, kteří Redux a jeho logiku neznají, doporučuji pro pochopení trochu nastudovat, protože když jsem sám podobný kód viděl poprvé, tak se mi zavařil mozek a to jsem v JavaScriptu nebyl zrovna nováček.
Také je potřeba počítat s tím, že data se načítají asynchronně až při jejich potřebě, takže je dobré mít v bloku spinner, který uživateli ukazuje, že dochází k načítání dat.
/wp-content/plugins/katuscak-gutenberg/gutenberg/blocks/authors/editor.js
import Select from 'react-select';
const {apiFetch} = wp;
const {registerBlockType} = wp.blocks;
const {PanelBody, PanelRow, Spinner} = wp.components;
const {registerStore, withSelect} = wp.data;
const {InnerBlocks, InspectorControls} = wp.editor;
const actions = {
setUsers(userAuthors) {
return {
type: 'SET_USERS',
userAuthors,
};
},
receiveUsers(path) {
return {
type: 'RECEIVE_USERS',
path,
};
},
};
registerStore('katuscak-gutenberg/authors', {
reducer(state = {userAuthors: {}}, action) {
switch (action.type) {
case 'SET_USERS':
return {
...state,
userAuthors: action.userAuthors,
};
}
return state;
},
actions,
selectors: {
receiveUsers(state) {
const {userAuthors} = state;
return userAuthors;
},
},
controls: {
RECEIVE_USERS(action) {
return apiFetch({path: action.path});
},
},
resolvers: {
* receiveUsers() {
const userAuthors = yield actions.receiveUsers('/katuscak-gutenberg/users/');
return actions.setUsers(userAuthors);
},
},
});
const block = registerBlockType('katuscak-gutenberg/authors', {
title: 'Autoři článku',
icon: 'admin-users',
category: 'layout',
attributes: {
user: {
type: 'string',
default: null,
},
},
edit: withSelect((select) => ({
userAuthors: select('katuscak-gutenberg/authors').receiveUsers(),
}))(props => {
const {attributes: {user}, userAuthors, className, setAttributes} = props;
const handleUsersChange = (user) => setAttributes({user: JSON.stringify(user)});
let selectedAuthors = [];
if (null !== user) {
selectedAuthors = JSON.parse(user);
}
if (!userAuthors.length) {
return (
<p className={className}>
<Spinner/>
Načítání dat
</p>
);
}
return [
<InspectorControls>
<PanelBody title="Autoři"
className="secure-block-inspector">
<PanelRow>
<Select
className={props.className + '__select'}
name='secure-block-users'
value={selectedAuthors}
onChange={handleUsersChange}
options={userAuthors}
isMulti='true'
/>
</PanelRow>
</PanelBody>
</InspectorControls>,
<div className={props.className}>
<span className={props.className + '__description'}>
<strong>Autoři článku: </strong>
{!selectedAuthors || selectedAuthors.length === 0 ?
<span> --- vyberte --- </span>
:
<span className={props.className + '__users'}>
{Object(selectedAuthors).map((value, key) =>
<span className={props.className + '__users_user'}>
<span className={props.className + '__users_user_name'}>
{value['label']}
</span>
</span>
)}
</span>
}
</span>
</div>
];
}),
save: (props) => (
<div className={props.className}>
<InnerBlocks.Content/>
</div>
)
});
export {block}
Jak použít data při renderování bloku?
WordPress přímo v PHP umožňuje vyrenderovat si blok úplně jinak, než je vlastně celou dobu v databázi uložený. To znamená, že se zvolenými uživateli lze následně více pracovat až když dojde k vykreslení článku
/wp-content/plugins/katuscak-gutenberg/katuscak-gutenberg.php
// ... další kód
function katuscak_gutenber_register_blocks()
{
// Pouze pokud je Gutenberg dostupný
if (!function_exists('register_block_type')) {
return;
}
register_block_type('katuscak-gutenberg/authors', [
'render_callback' => 'katuscak_gutenberg_authors_render',
]);
}
katuscak_gutenber_register_blocks();
function katuscak_gutenberg_authors_render($attributes, $content)
{
$users = json_decode($attributes["user"]);
var_dump($users);
}
// ... další kód
Jak to potom vypadá při použití?
Kompletní kód (celý plugin do WP) najdete na: github.com/MichalKatuscak/gutenberg-blocks
Zdroje:
https://developer.wordpress.org/rest-api/
https://developer.wordpress.org/block-editor/packages/packages-data/
https://react-redux.js.org/
Znáte někoho, komu by článek mohl pomoct? Zasdílejte mu ho :)