Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Gutenberg sous le capot, modules réutilisables

625 views

Published on

Gutenberg arrive, ça change tout pour ce qui est de la création de contenu dans WordPress. Mais ce que vous ne savez pas c’est que Gutenberg a le potentiel pour changer beaucoup de choses pour les développeurs de plugins et de thèmes WordPress et même à l’extérieur de la communauté WordPress.

De la gestion des données de votre plugin, la gestion des dates, l’internationalisation à l’interface UI, Gutenberg est une mine d’or qui ne demande qu’à être exploitée. Explorons ensemble l’architecture modulaire de Gutenberg et apprenons à réutiliser ses modules pour ses propres projets.

Published in: Internet
  • Be the first to comment

  • Be the first to like this

Gutenberg sous le capot, modules réutilisables

  1. 1. Riad Benguella @riadbenguella riad.blog Gutenberg sous le capot
  2. 2. CHAPTER I Vue Globale
  3. 3. “ ” MATT MULLENWEG Learn JavaScript Deeply The State of the Word 2015
  4. 4. Technologies
  5. 5. Monolithique Modulaire
  6. 6. Modules Gutenberg • Un module = un script wordpress • Un module peut avoir une feuille de style associée • Chaque module est disponible dans wp.* • Les modules génériques sont sur npm
  7. 7. Utiliser un script Gutenberg wp_register_script( ‘my-plugin-script’, ‘path/to/my-script’, array( ‘wp-components’ ), ); wp_register_style( ‘my-plugin-style’, ‘path/to/my-style’, array( ‘wp-components’ ), );
  8. 8. CHAPTER II Plugin Fil Rouge
  9. 9. CHAPTER III Module Element
  10. 10. Abstraction on top of React wp_register_script( ‘my-plugin-script’, ‘path/to/my-script’, array( ‘wp-element’ ), ); Ajout de la dépendance
  11. 11. const { render, createElement: el } = wp.element; function Hello({ name }) { Return <h1>{ ‘Hello ‘ + name }</h1>; // el( ‘h1’, {}, ‘Hello’ + name ) } render( <Hello name=“Lyon” />, document.querySelector( ‘#root’ ) ); Abstraction on top of React
  12. 12. const { render, createElement: el } = wp.element; function Hello({ name }) { Return <h1>{ ‘Hello ‘ + name }</h1>; // el( ‘h1’, {}, ‘Hello’ + name ) } render( <Hello name=“Lyon” />, document.querySelector( ‘#root’ ) ); Abstraction on top of React
  13. 13. const { render, createElement: el } = wp.element; function Hello({ name }) { Return <h1>{ ‘Hello ‘ + name }</h1>; // el( ‘h1’, {}, ‘Hello’ + name ) } render( <Hello name=“Lyon” />, document.querySelector( ‘#root’ ) ); Abstraction on top of React
  14. 14. À retenir wp.element.createElement <=> JSX pour créer des éléments wp.element.render pour afficher un composant.
  15. 15. CHAPTER |V Module Plugins
  16. 16. The new Meta Boxes? Un module générique pour étendre l’UI de WordPress
  17. 17. wp_register_script( ‘my-plugin-script’, ‘path/to/my-script’, array( ‘wp-element’, ‘wp-plugins’, ‘wp-edit-post’ ), ); Ajout de la dépendance The new meta boxes
  18. 18. const { registerPlugin } = wp.plugins; const { PluginSidebar, PluginMoreMenuItem } = wp.editPost; The new meta boxes
  19. 19. The new meta boxes const { registerPlugin } = wp.plugins; const { PluginSidebar, PluginMoreMenuItem } = wp.editPost;
  20. 20. const DropIt = () => ( <Fragment> <PluginSidebar name="dropit-sidebar" title=“Drop it"> Bienvenue dans Drop it </PluginSidebar> <PluginMoreMenuItem icon="art" target="dropit-sidebar" > Open Drop it </PluginMoreMenuItem> </Fragment> ); The new meta boxes
  21. 21. The new meta boxes const DropIt = () => ( <Fragment> <PluginSidebar name="dropit-sidebar" title=“Drop it"> Bienvenue dans Drop it </PluginSidebar> <PluginMoreMenuItem icon="art" target="dropit-sidebar" > Open Drop it </PluginMoreMenuItem> </Fragment> );
  22. 22. The new meta boxes registerPlugin("dropit", { render: DropIt });
  23. 23. À retenir • wp.plugins.registerPlugin pour définir un plugin • Chaque plugin peut afficher plusieurs “Slots” • Exemple: Sidebar, MenuItem… https://github.com/WordPress/gutenberg/tree/master/edit-post
  24. 24. CHAPTER V Module Components
  25. 25. Reusable UI components Une collection de composants graphiques pour construire son interface
  26. 26. Ajout de la dépendance Reusable components wp_register_script( ‘my-plugin-script’, ‘path/to/my-script’, array( ‘wp-components’ ), ); wp_register_style( ‘my-plugin-style’, ‘path/to/my-style’, array( ‘wp-components’ ), );
  27. 27. Le composant React de base
  28. 28. const { Component } = wp.element; const searchPhotos = ( query ) => { // Do something and return a promise of photos } class PhotoList extends Component { state = { query: ‘’, photos: [] }; changeQuery = event => this.setState( { query: event.target.value } ); search = () => searchPhotos( this.state.query ).then( photos => this.setState( { photos } ); ); }
  29. 29. const { Component } = wp.element; const searchPhotos = ( query ) => { // Do something and return a promise of photos } class PhotoList extends Component { state = { query: ‘’, photos: [] }; changeQuery = event => this.setState( { query: event.target.value } ); search = () => searchPhotos( this.state.query ).then( photos => this.setState( { photos } ); ); }
  30. 30. const { Component } = wp.element; const searchPhotos = ( query ) => { // Do something and return a promise of photos } class PhotoList extends Component { state = { query: ‘’, photos: [] }; changeQuery = event => this.setState( { query: event.target.value } ); search = () => searchPhotos( this.state.query ).then( photos => this.setState( { photos } ); ); }
  31. 31. const { Component } = wp.element; const searchPhotos = ( query ) => { // Do something and return a promise of photos } class PhotoList extends Component { state = { query: ‘’, photos: [] }; changeQuery = event => this.setState( { query: event.target.value } ); search = () => searchPhotos( this.state.query ).then( photos => this.setState( { photos } ); ); }
  32. 32. const { Component } = wp.element; const searchPhotos = ( query ) => { // Do something and return a promise of photos } class PhotoList extends Component { state = { query: ‘’, photos: [] }; changeQuery = event => this.setState( { query: event.target.value } ); search = () => searchPhotos( this.state.query ).then( photos => this.setState( { photos } ); ); }
  33. 33. La méthode render: Réutiliser des composants
  34. 34. const { IconButton } = wp.components; class PhotoList extends Component { // Remaining methods and properties go here. render() { return ( <div> <form onSubmit={this.search}> <input value={this.state.query} onChange={this. changeQuery} /> <IconButton icon=“search” type=“submit” /> </form> </div> ); }
  35. 35. const { IconButton } = wp.components; class PhotoList extends Component { // Remaining methods and properties go here. render() { return ( <div> <form onSubmit={this.search}> <input value={this.state.query} onChange={this. changeQuery} /> <IconButton icon=“search” type=“submit” /> </form> </div> ); }
  36. 36. const { IconButton } = wp.components; class PhotoList extends Component { // Remaining methods and properties go here. render() { return ( <div> <form onSubmit={this.search}> <input value={this.state.query} onChange={this. changeQuery} /> <IconButton icon=“search” type=“submit” /> </form> </div> ); }
  37. 37. La méthode render: Afficher les photos
  38. 38. const { IconButton } = wp.components; class PhotoList extends Component { render() { return ( <div> <form /*… */ /> { this.state.photos.map( photo => ( <Photo key={photo.id} photo={photo} /> ) ) } </div> ); } }
  39. 39. class Photo extends Component { onAddPhoto() => {} render() { return ( <div> <img src={this.props.photo.url} /> <IconButton icon=“plus” onClick={ this.onAddPhoto } /> </div> ); } }
  40. 40. class Photo extends Component { onAddPhoto() => {} render() { return ( <div> <img src={this.props.photo.url} /> <IconButton icon=“plus” onClick={ this.onAddPhoto } /> </div> ); } }
  41. 41. class Photo extends Component { onAddPhoto() => {} render() { return ( <div> <img src={this.props.photo.url} /> <IconButton icon=“plus” onClick={ this.onAddPhoto } /> </div> ); } }
  42. 42. À retenir • On peut facilement composer différents composants pour faire une UI riche • wp.components met à disposition des composants prêt à être utilisés: • UI: Button, IconButton, Dropdown, Tooltip, Popover… • A11Y: NavigableContainer, withFocusReturn,… https://github.com/WordPress/gutenberg/tree/master/components
  43. 43. CHAPTER VI Module Data
  44. 44. Chaque module WP peut mettre des données à disposition des plugins.
  45. 45. wp_register_script( ‘my-plugin-script’, ‘path/to/my-script’, array( ‘wp-data’, ‘wp-editor` ), ); Ajout de la dépendance
  46. 46. const { withSelect } = wp.data; function MyBlockCount( { count } ) { return “Nombre de blocs: “ + count; } export default withSelect( ( select ) => { return { count: select( ‘core/editor’ ).getBlockCount() }; } )( MyBlockCount ); Exemple: Récupérer des données
  47. 47. const { withSelect } = wp.data; function MyBlockCount( { count } ) { return “Nombre de blocs: “ + count; } export default withSelect( ( select ) => { return { count: select( ‘core/editor’ ).getBlockCount() }; } )( MyBlockCount ); Exemple: Récupérer des données
  48. 48. const { withSelect } = wp.data; function MyBlockCount( { count } ) { return “Nombre de blocs: “ + count; } export default withSelect( ( select ) => { return { count: select( ‘core/editor’ ).getBlockCount() }; } )( MyBlockCount ); Exemple: Récupérer des données https://github.com/WordPress/gutenberg/blob/master/editor/store/selectors.js
  49. 49. const { withDispatch } = wp.data; class Photo extends Component { /** Photo component with its render function **/ } export default withDispatch( ( dispatch ) => { return { insertBlock: select( ‘core/editor’ ).insertBlock }; } )( Photo ); Lancer des actions
  50. 50. const { withDispatch } = wp.data; class Photo extends Component { /** Photo component with its render function **/ } export default withDispatch( ( dispatch ) => { return { insertBlock: select( ‘core/editor’ ).insertBlock }; } )( Photo ); Lancer des actions
  51. 51. const { withDispatch } = wp.data; class Photo extends Component { onAddPhoto() => { this.props.insertBlock( ‘core/image’, { url: this.props.photo.url } ); } } export default withDispatch( ( dispatch ) => { return { insertBlock: select( ‘core/editor’ ).insertBlock Lancer des actions https://github.com/WordPress/gutenberg/blob/master/editor/store/actions.js
  52. 52. À retenir • wp.data.withSelect pour récupérer des données • wp.data.withDispatch pour lancer des actions • Chaque module met à disposition: • Des selecteurs pour récupérer des données • Des actions pour effectuer des actions • Utiliser wp.data pour gérer vos données. https://github.com/WordPress/gutenberg/tree/master/data
  53. 53. CHAPTER VII Module i18n
  54. 54. wp_register_script( ‘my-plugin-script’, ‘path/to/my-script’, array( ‘wp-i18n’ ), ); Ajout de la dépendance
  55. 55. const { __ } = wp.i18n; class PhotoList extends Component { /** **/ render() { return ( <div> <form onSubmit={this.search}> <input value={this.state.query} onChange={this. changeQuery} placeholder={ __( ‘Search’, ‘dropit’ ) } /> <IconButton icon=“search” type=“submit” /> </form> </div> ); }
  56. 56. const { __ } = wp.i18n; class PhotoList extends Component { /** **/ render() { return ( <div> <form onSubmit={this.search}> <input value={this.state.query} onChange={this. changeQuery} placeholder={ __( ‘Search’, ‘dropit’ ) } /> <IconButton icon=“search” type=“submit” /> </form> </div> ); }
  57. 57. À retenir • wp.i18n.__ pour internationaliser un texte. • wp.i18n.setLocaleData pour fournir les chaines traduites • Inclut des outils pour faciliter la génération de .pot et la traduction au niveau de wp.org https://github.com/WordPress/packages/tree/master/packages/i18n
  58. 58. CHAPTER VIII Autres
  59. 59. À retenir • wp.a11y.speak pour annoncer des messages. • wp.date.format pour formater les dates • wp.viewport pour gérer la taille de l’écran (responsive)
  60. 60. CHAPTER IX The future
  61. 61. Suivre ici: github.com/wordpress/packages github.com/wordpress/gutenberg
  62. 62. Documentation wordpress.org/gutenberg/handbook/ READMEs
  63. 63. Join the conversation: #core-editor, mercredi 16:00 #core-js, mardi 15:00
  64. 64. Et notre plugin alors? wordpress.org/plugins/dropit
  65. 65. Venez me voir, parlons Gutenberg

×