Utilisation des options pour stocker des données dans l’éditeur de blocs WordPress (Gutenberg)
Nous avons déjà exploré le stockage des données de l’éditeur de blocs WordPress (Gutenberg) dans les attributs de bloc et dans la méta post, mais saviez-vous que vous pouvez stocker et récupérer dans le tableau des options WordPress en important apidepuis @wordpress/api.
Dans ce guide, nous examinons ce que vous écririez classiquement en PHP comme update_optionet get_option.
Afin de mettre en œuvre cela, nous devons tirer parti du cycle de vie de React, nous allons donc envisager de créer un composant React en important Componentà partir de @wordpress/element.
Conditions préalables
- Se familiariser avec la création de plugins pour WordPress Gutenberg
- Familiarisez-vous avec les blocs dynamiques et le rendu côté serveur
- Comprendre comment vous pouvez créer des méta-boîtes dans Gutenberg
Cette dernière exigence est utile pour l’interface utilisateur que nous allons utiliser dans ce guide, mais dans les applications du monde réel, il est probable que vous utiliseriez cette méthode dans une barre latérale ou une page d’options.
Enregistrez les options en PHP
Avant de pouvoir utiliser une option en JavaScript, nous devons nous assurer que nous l’avons enregistrée dans PHP en utilisant register_settinget que l’ show_in_restargument a été défini sur true.
Suite au guide Dynamic Block, ouvrez le fichier PHP racine du plugin (dans ce cas wholesome-plugin.php) et ajoutez le code suivant au bas de ce fichier après toutes les autres fonctions :
function wholesomecode_wholesome_plugin_register_settings() {
register_setting(
'wholesomecode_wholesome_plugin_settings',
'wholesomecode_wholesome_plugin_example_text',
[
'default' => '',
'show_in_rest' => true,
'type' => 'string',
]
);
}
add_action( 'init', 'wholesomecode_wholesome_plugin_register_settings' );
Ce code enregistre un champ méta appelé wholesomecode_wholesome_plugin_block_textpour le wholesomecode_wholesome_plugin_settingsgroupe d’options. Cela garantit également que l’API REST peut accéder à ce champ méta avec la show_in_restvaleur définie sur true.
Créer le composant
Ouvrez le /src/edit.jsfichier, nous allons modifier quelque peu la structure de ce fichier afin de pouvoir sortir notre fichier Component.
Coupez et collez l’intégralité de ce bloc de code dans le /src/edit.jsfichier, nous couvrirons ce qu’il fait dans un instant :
import { __ } from '@wordpress/i18n';
import { useBlockProps } from '@wordpress/block-editor';
import {
Panel,
PanelBody,
TextControl,
} from '@wordpress/components';
import { Component } from '@wordpress/element';
import './editor.scss';
class OptionsExample extends Component {
constructor() {
super( ...arguments );
this.state = { exampleText: '' };
}
render() {
const { exampleText } = this.state;
return (<Panel>
<PanelBody
title={ __( 'Example Meta Box', 'wholesome-plugin') }
icon="admin-plugins"
>
<TextControl
help={ __( 'This is an example text field.', 'wholesome-plugin') }
label={ __( 'Example Text', 'wholesome-plugin') }
onChange={ (exampleText) => this.setState( { exampleText }) }
value={ exampleText }
/>
</PanelBody>
</Panel>) }
}
export default function Edit( props) {
return (<div { ...useBlockProps() }>
<OptionsExample { ...props }/>
</div>
);
}
Vous reconnaîtrez peut-être que l’interface utilisateur que nous avons mise en place est exactement la même que celle du guide Gutenberg Meta Box, où nous avons utilisé les méta-attributs post. Vous pouvez également remarquer que nous n’obtenons pas ou ne définissons pas d’informations à l’aide d’options pour le moment, et à la place, nous utilisons simplement le composant state.
Utilisation de l’état
La raison pour laquelle nous avons créé un composant personnalisé, puis l’avons transmis à notre Editfonction, est que nous pouvons tirer parti de l’état. Nous avons fait cela parce que :
- Nous allons créer une fonction pour charger les options de l’API, et nous devons stocker cela dans l’état afin que nos composants puissent le lire
- Nous ne voulons pas que l’API mette à jour les options dès que le texte change dans notre zone de texte, nous avons donc besoin d’une fonction pour enregistrer l’état dans les options via l’API une fois la publication enregistrée
L’utilisation de l’état est assez simple. Dans le constructeur, nous initialisons l’état comme suit :
this.state = { exampleText: '' };
Et dans le composant, nous y accédons de la même manière que nous avons accédé aux attributs dans le guide précédent :
const { exampleText } = this.state;
La différence étant, sur notre onChangeméthode, au lieu d’utiliser setAttributesnous utilisons this.setState.
Obtenir des options de l’API
En haut du document import apidepuis @wordpress/api:
import api from '@wordpress/api';
Ajoutez une nouvelle propriété à l’endroit où l’état est initialisé de isAPILoaded. Nous en aurons besoin pour nous assurer que nous n’essayons pas d’accéder à l’API ou de rendre le composant avant le chargement de l’API.
this.state = {
exampleText: '',
isAPILoaded: false,
};
Maintenant, dans le composant que nous avons créé, ajoutez un bloc de code sous le constructeur appelé componentDidMount. Il s’agit d’une méthode de cycle de vie React, qui est appelée après qu’un composant a été ajouté au DOM.
Dans ce bloc de code, ajoutez ce qui suit :
componentDidMount() {
api.loadPromise.then(() => {
this.settings = new api.models.Settings();
const { isAPILoaded } = this.state;
if (isAPILoaded === false) {
this.settings.fetch().then( (response) => {
this.setState( {
exampleText: response[ 'wholesomecode_wholesome_plugin_example_text' ],
isAPILoaded: true,
} );
} );
}
} );
}
Ici, nous accédons à l’option que nous avons enregistrée précédemment avec la register_settingfonction.
Ce bloc de code effectue les opérations suivantes :
- Obtient les paramètres de l’API WordPress Guttenberg Settings.
- Obtient
isAPILoadedde l’état - Si l’API n’a pas été chargée, elle récupère les paramètres de l’API dans un
response - Nous définissons ensuite l’état pour mettre à jour l’état avec l’option à laquelle nous voulons accéder et définissons l’
isAPILoadedétat sur true
Arrêter le rendu de bloc sans paramètres
Nous ne voulons pas que notre bloc soit rendu avant que les paramètres aient été renseignés. Pour prendre soin de cela, nous pouvons importer un PlaceHolder et un Spinner depuis $wordpress/components:
import {
Panel,
PanelBody,
Placeholder,
Spinner,
TextControl,
} from '@wordpress/components';
Ensuite, dans la méthode de rendu du composant, assurez-vous d’obtenir isAPILoadedde l’état et de sortir le Placeholderet Spinnersi ce n’est pas le cas :
const {
exampleText,
isAPILoaded,
} = this.state;
if (! isAPILoaded) {
return (<Placeholder>
<Spinner />
</Placeholder>
);
}
De cette façon, si les options ne sont pas chargées, nous obtenons un bel espace réservé jusqu’à ce que le composant se charge :
Espace réservé et Spinner
Accrocher à Gutenberg sur Save
Maintenant que nous lisons les options de la table des options, nous avons besoin d’un moyen de sauvegarder ces options lorsque nous les modifions. Pour ce faire, nous allons au subscribemagasin de données WordPress Gutenberg, qui indiquera quand quelque chose a changé.
En utilisant cela, nous allons créer un écouteur pour le moment où le message est enregistré et enregistrer nos paramètres lorsque cela se produit.
Pour ce faire, importez subscribeet selectdepuis @wordpress/data.
import { select, subscribe } from '@wordpress/data';
Ensuite, en haut du componentDidMountbloc de code, écrivez ce qui suit :
subscribe(() => {
const { exampleText } = this.state;
const isSavingPost = select('core/editor').isSavingPost();
const isAutosavingPost = select('core/editor').isAutosavingPost();
if (isAutosavingPost) {
return;
}
if (! isSavingPost) {
return;
}
const settings = new api.models.Settings( {
[ 'wholesomecode_wholesome_plugin_example_text' ]: exampleText,
} );
settings.save();
});
Le code effectue les opérations suivantes :
- Vérifie si le message est enregistré
- Vérifiez si la sauvegarde est une sauvegarde automatique
- Si la publication est en cours d’enregistrement et qu’il ne s’agit pas d’un enregistrement automatique, poussez les nouveaux paramètres dans l’API des paramètres
- Déclenchez une sauvegarde de l’API Settings.
Un petit hack
Nous pourrions laisser notre code comme ceci, mais comme nous mettons nos paramètres dans un bloc, et non dans une barre latérale ou un autre composant de l’éditeur, si nous modifions l’une des options, et rien d’autre dans l’éditeur, le bouton "enregistrer" ne devenir actif.
C’est parce que nous n’utilisons setAttributesrien pour modifier le code réel du bloc.
Nous pouvons contourner ce problème en éditant simplement une autre partie du message ou en ajoutant un petit hack dans le TextControlcode :
onChange={ (exampleText) => { this.setState( { exampleText } ); setAttributes( { exampleText }) } }
N’oubliez pas de mettre cette ligne de code en haut de la méthode de rendu pour extraire setAttributesdu props(car nous utilisons un composant, nous accédons à des accessoires légèrement différents avec this.
const { setAttributes } = this.props;
Désormais, lorsque nous modifions notre attribut, un "faux" attribut va changer, ce qui fait penser à l’éditeur que nous pouvons maintenant enregistrer le message.
C’est un peu hacky, mais pour ce cas d’utilisation, il fait ce dont nous avons besoin.
EditLe code entier
Voici tout le code dont vous avez besoin pour la Editméthode :
j’importe {} de ‘ @wordpress /i18n’ ; importer l’API depuis ‘ @wordpress /api’ ; import { useBlockProps } de ‘ @wordpress /block-editor’ ; import { Panel, PanelBody, Placeholder, Spinner, TextControl, } from ‘ @wordpress /components’ ; importer { sélectionner, s’abonner } à partir de ‘ @wordpress /data’ ; import { Component } from ‘ @wordpress /element’;
importer ‘./editor.scss’ ;
class OptionsExample extend Component { constructeur() { super( …arguments );
this.state = {
exampleText: '',
isAPILoaded: false,
};
}
componentDidMount() {
subscribe( () => {
const { exampleText } = this.state;
const isSavingPost = select('core/editor').isSavingPost();
const isAutosavingPost = select('core/editor').isAutosavingPost();
if (isAutosavingPost) {
return;
}
if (! isSavingPost) {
return;
}
const settings = new api.models.Settings( {
[ 'wholesomecode_wholesome_plugin_example_text' ]: exampleText,
} );
settings.save();
});
api.loadPromise.then( () => {
this.settings = new api.models.Settings();
const { isAPILoaded } = this.state;
if (isAPILoaded === false) {
this.settings.fetch().then( (response) => {
this.setState( {
exampleText: response[ 'wholesomecode_wholesome_plugin_example_text' ],
isAPILoaded: true,
} );
} );
}
} );
}
render() {
const {
exampleText,
isAPILoaded,
} = this.state;
const { setAttributes } = this.props;
if (! isAPILoaded) {
return (<Placeholder>
<Spinner />
</Placeholder>
);
}
return (<Panel>
<PanelBody
title={ __( 'Example Meta Box', 'wholesomecode') }
icon="admin-plugins"
>
<TextControl
help={ __( 'This is an example text field.', 'wholesome-plugin') }
label={ __( 'Example Text', 'wholesome-plugin') }
onChange={ (exampleText) => { this.setState( { exampleText } ); setAttributes( { exampleText }) } }
value={ exampleText }
/>
</PanelBody>
</Panel>) }
}
exporter la fonction par défaut Edit( props) { return (
); }
### Remove the Attributes
Option 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.
Render the Output
Because we have saved our attribute as settings in the WordPress options table, we could output this anywhere in WordPress using `get_option`:
get_option( ‘wholesomecode_wholesome_plugin_block_text’, " );
Continuing 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.
With this in mind, let’s update our `register_block_type` to output the option:
register_block_type( ‘wholesomecode/wholesome-plugin’, array( ‘editor_script’ => ‘wholesomecode-wholesome-plugin-block-editor’, ‘editor_style’ => ‘wholesomecode-wholesome-plugin-block-editor’, ‘render_callback’ = > function( $attributes, $content) { $example_text = get_option( ‘wholesomecode_wholesome_plugin_example_text’ ); return "
$exemple_texte
"; }, ‘style’ => ‘wholesomecode-wholesome-plugin-block’,) );
Note 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.
5.
Using the Block
--------------------
Putting it all together, let’s see the block in action:
:
importer {} de ‘ @wordpress /i18n’ ; importer l’API depuis ‘ @wordpress /api’ ; import { useBlockProps } de ‘ @wordpress /block-editor’ ; import { Panel, PanelBody, PanelRow, Placeholder, SelectControl, Spinner, TextControl, ToggleControl, } from ‘ @wordpress /components’ ; importer { sélectionner, s’abonner } à partir de ‘ @wordpress /data’ ; import { Component } from ‘ @wordpress /element’;
importer ‘./editor.scss’ ;
class OptionsExample extend Component { constructeur() { super( …arguments );
this.state = {
exampleSelect: '',
exampleText: '',
exampleText2: '',
exampleText3: '',
exampleToggle: false,
isAPILoaded: false,
};
}
componentDidMount() {
subscribe( () => {
const {
exampleSelect,
exampleText,
exampleText2,
exampleText3,
exampleToggle,
} = this.state;
const isSavingPost = select('core/editor').isSavingPost();
const isAutosavingPost = select('core/editor').isAutosavingPost();
if (isAutosavingPost) {
return;
}
if (! isSavingPost) {
return;
}
const settings = new api.models.Settings( {
[ 'wholesomecode_wholesome_plugin_example_select' ]: exampleSelect,
[ 'wholesomecode_wholesome_plugin_example_text' ]: exampleText,
[ 'wholesomecode_wholesome_plugin_example_text_2' ]: exampleText2,
[ 'wholesomecode_wholesome_plugin_example_text_3' ]: exampleText3,
[ 'wholesomecode_wholesome_plugin_example_toggle' ]: exampleToggle,
} );
settings.save();
});
api.loadPromise.then( () => {
this.settings = new api.models.Settings();
const { isAPILoaded } = this.state;
if (isAPILoaded === false) {
this.settings.fetch().then( (response) => {
this.setState( {
exampleSelect: response[ 'wholesomecode_wholesome_plugin_example_select' ],
exampleText: response[ 'wholesomecode_wholesome_plugin_example_text' ],
exampleText2: response[ 'wholesomecode_wholesome_plugin_example_text_2' ],
exampleText3: response[ 'wholesomecode_wholesome_plugin_example_text_3' ],
exampleToggle: Boolean( response[ 'wholesomecode_wholesome_plugin_example_toggle' ] ),
isAPILoaded: true,
} );
} );
}
} );
}
render() {
const {
exampleSelect,
exampleText,
exampleText2,
exampleText3,
exampleToggle,
isAPILoaded,
} = this.state;
if (! isAPILoaded) {
return (<Placeholder>
<Spinner />
</Placeholder>
);
}
return (<Panel>
<PanelBody
title={ __( 'Example Meta Box', 'wholesome-plugin') }
icon="admin-plugins"
>
<SelectControl
help={ __( 'An example dropdown field.', 'wholesome-plugin') }
label={ __( 'Example Select', 'wholesome-plugin') }
onChange={ (exampleSelect) => this.setState( { exampleSelect }) }
options={ [
{
label: __( 'Please Select...', 'wholesome-plugin' ),
value: '',
},
{
label: __( 'Option 1', 'wholesome-plugin' ),
value: 'option-1',
},
{
label: __( 'Option 2', 'wholesome-plugin' ),
value: 'option-2',
},
] }
value={ exampleSelect }
/>
<TextControl
help={ __( 'This is an example text field.', 'wholesome-plugin') }
label={ __( 'Example Text', 'wholesome-plugin') }
onChange={ (exampleText) => this.setState( { exampleText }) }
value={ exampleText }
/>
<PanelRow>
<TextControl
help={ __( 'Use PanelRow to place controls inline.', 'wholesome-plugin') }
label={ __( 'Example Text 2', 'wholesome-plugin') }
onChange={ (exampleText2) => this.setState( { exampleText2 }) }
value={ exampleText2 }
/>
<TextControl
help={ __( 'This control is inline.', 'wholesome-plugin') }
label={ __( 'Example Text 3', 'wholesome-plugin') }
onChange={ (exampleText3) => this.setState( { exampleText3 }) }
value={ exampleText3 }
/>
</PanelRow>
<ToggleControl
checked={ exampleToggle }
help={ __( 'An example toggle.', 'wholesome-plugin') }
label={ __( 'Example Toggle', 'wholesome-plugin') }
onChange={ (exampleToggle) => this.setState( { exampleToggle }) }
/>
</PanelBody>
</Panel>) }
}
exporter la fonction par défaut Edit( props) { return (
); } `
Voici le résultat :
Options supplémentaires
- Découvrez comment créer des blocs enfants imbriqués avec le
InnerBlockscomposant - Jetez un œil à l’utilisation des champs post-méta dans les blocs Gutenberg
- Jetez un œil à la création de boîtes méta personnalisées dans Gutenberg