Gutenberg sous le capot, modules réutilisables

Riad Benguella
Riad BenguellaWeb Developer at home
Riad Benguella @riadbenguella riad.blog
Gutenberg sous le capot
CHAPTER I
Vue Globale
Gutenberg sous le capot, modules réutilisables
“
”
MATT MULLENWEG
Learn JavaScript Deeply
The State of the Word 2015
Technologies
Monolithique
Modulaire
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
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’ ),
);
CHAPTER II
Plugin
Fil Rouge
CHAPTER III
Module Element
Abstraction on top of React
wp_register_script(
‘my-plugin-script’,
‘path/to/my-script’,
array( ‘wp-element’ ),
);
Ajout de la dépendance
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
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
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
À retenir
wp.element.createElement <=> JSX pour créer des éléments
wp.element.render pour afficher un composant.
CHAPTER |V
Module Plugins
The new Meta Boxes?
Un module générique pour étendre l’UI de
WordPress
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
const { registerPlugin } = wp.plugins;
const { PluginSidebar, PluginMoreMenuItem } = wp.editPost;
The new meta boxes
The new meta boxes
const { registerPlugin } = wp.plugins;
const { PluginSidebar, PluginMoreMenuItem } = wp.editPost;
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
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>
);
The new meta boxes
registerPlugin("dropit", {
render: DropIt
});
Gutenberg sous le capot, modules réutilisables
À 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
CHAPTER V
Module Components
Reusable UI components
Une collection de composants graphiques
pour construire son interface
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’ ),
);
Le composant React de base
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 } );
);
}
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 } );
);
}
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 } );
);
}
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 } );
);
}
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 } );
);
}
La méthode render:
Réutiliser des composants
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>
);
}
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>
);
}
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>
);
}
La méthode render:
Afficher les photos
const { IconButton } = wp.components;
class PhotoList extends Component {
render() {
return (
<div>
<form /*… */ />
{ this.state.photos.map( photo => (
<Photo key={photo.id} photo={photo} />
) ) }
</div>
);
}
}
class Photo extends Component {
onAddPhoto() => {}
render() {
return (
<div>
<img src={this.props.photo.url} />
<IconButton icon=“plus” onClick={ this.onAddPhoto } />
</div>
);
}
}
class Photo extends Component {
onAddPhoto() => {}
render() {
return (
<div>
<img src={this.props.photo.url} />
<IconButton icon=“plus” onClick={ this.onAddPhoto } />
</div>
);
}
}
class Photo extends Component {
onAddPhoto() => {}
render() {
return (
<div>
<img src={this.props.photo.url} />
<IconButton icon=“plus” onClick={ this.onAddPhoto } />
</div>
);
}
}
Gutenberg sous le capot, modules réutilisables
À 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
CHAPTER VI
Module Data
Chaque module WP peut mettre des
données à disposition des plugins.
wp_register_script(
‘my-plugin-script’,
‘path/to/my-script’,
array( ‘wp-data’, ‘wp-editor` ),
);
Ajout de la dépendance
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
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
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
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
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
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
À 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
CHAPTER VII
Module i18n
wp_register_script(
‘my-plugin-script’,
‘path/to/my-script’,
array( ‘wp-i18n’ ),
);
Ajout de la dépendance
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>
);
}
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>
);
}
À 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
CHAPTER VIII
Autres
À 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)
CHAPTER IX
The future
Suivre ici:
github.com/wordpress/packages
github.com/wordpress/gutenberg
Documentation
wordpress.org/gutenberg/handbook/
READMEs
Join the conversation:
#core-editor, mercredi 16:00
#core-js, mardi 15:00
Et notre plugin alors?
wordpress.org/plugins/dropit
Venez me voir, parlons Gutenberg
1 of 68

Recommended

Speed up the site building with Drupal's Bootstrap Layout Builder by
Speed up the site building with Drupal's Bootstrap Layout BuilderSpeed up the site building with Drupal's Bootstrap Layout Builder
Speed up the site building with Drupal's Bootstrap Layout BuilderDrupalCamp Kyiv
763 views34 slides
DRUPAL 8 STORAGES OVERVIEW by
DRUPAL 8 STORAGES OVERVIEWDRUPAL 8 STORAGES OVERVIEW
DRUPAL 8 STORAGES OVERVIEWDrupalCamp Kyiv
3.1K views47 slides
Sane Async Patterns by
Sane Async PatternsSane Async Patterns
Sane Async PatternsTrevorBurnham
14.6K views44 slides
Introduction to Vue.js by
Introduction to Vue.jsIntroduction to Vue.js
Introduction to Vue.jsMeir Rotstein
316 views27 slides
A New Baseline for Front-End Devs by
A New Baseline for Front-End DevsA New Baseline for Front-End Devs
A New Baseline for Front-End DevsRebecca Murphey
2.3K views64 slides
Backbone.js — Introduction to client-side JavaScript MVC by
Backbone.js — Introduction to client-side JavaScript MVCBackbone.js — Introduction to client-side JavaScript MVC
Backbone.js — Introduction to client-side JavaScript MVCpootsbook
3K views60 slides

More Related Content

What's hot

[FEConf Korea 2017]Angular 컴포넌트 대화법 by
[FEConf Korea 2017]Angular 컴포넌트 대화법[FEConf Korea 2017]Angular 컴포넌트 대화법
[FEConf Korea 2017]Angular 컴포넌트 대화법Jeado Ko
2.4K views73 slides
Planbox Backbone MVC by
Planbox Backbone MVCPlanbox Backbone MVC
Planbox Backbone MVCAcquisio
5.6K views52 slides
JSLab. Алексей Волков. "React на практике" by
JSLab. Алексей Волков. "React на практике"JSLab. Алексей Волков. "React на практике"
JSLab. Алексей Волков. "React на практике"GeeksLab Odessa
660 views42 slides
AngularJS by
AngularJSAngularJS
AngularJSLearningTech
691 views27 slides
Mulberry: A Mobile App Development Toolkit by
Mulberry: A Mobile App Development ToolkitMulberry: A Mobile App Development Toolkit
Mulberry: A Mobile App Development ToolkitRebecca Murphey
1.9K views35 slides
React, Redux and es6/7 by
React, Redux and es6/7React, Redux and es6/7
React, Redux and es6/7Dongho Cho
1.2K views57 slides

What's hot(20)

[FEConf Korea 2017]Angular 컴포넌트 대화법 by Jeado Ko
[FEConf Korea 2017]Angular 컴포넌트 대화법[FEConf Korea 2017]Angular 컴포넌트 대화법
[FEConf Korea 2017]Angular 컴포넌트 대화법
Jeado Ko2.4K views
Planbox Backbone MVC by Acquisio
Planbox Backbone MVCPlanbox Backbone MVC
Planbox Backbone MVC
Acquisio5.6K views
JSLab. Алексей Волков. "React на практике" by GeeksLab Odessa
JSLab. Алексей Волков. "React на практике"JSLab. Алексей Волков. "React на практике"
JSLab. Алексей Волков. "React на практике"
GeeksLab Odessa660 views
Mulberry: A Mobile App Development Toolkit by Rebecca Murphey
Mulberry: A Mobile App Development ToolkitMulberry: A Mobile App Development Toolkit
Mulberry: A Mobile App Development Toolkit
Rebecca Murphey1.9K views
React, Redux and es6/7 by Dongho Cho
React, Redux and es6/7React, Redux and es6/7
React, Redux and es6/7
Dongho Cho1.2K views
Михаил Крайнюк - Form API + Drupal 8: Form and AJAX by DrupalSib
Михаил Крайнюк - Form API + Drupal 8: Form and AJAXМихаил Крайнюк - Form API + Drupal 8: Form and AJAX
Михаил Крайнюк - Form API + Drupal 8: Form and AJAX
DrupalSib757 views
준비하세요 Angular js 2.0 by Jeado Ko
준비하세요 Angular js 2.0준비하세요 Angular js 2.0
준비하세요 Angular js 2.0
Jeado Ko7K views
Meet Magento Sweden - Magento 2 Layout and Code Compilation for Performance by Ivan Chepurnyi
Meet Magento Sweden - Magento 2 Layout and Code Compilation for PerformanceMeet Magento Sweden - Magento 2 Layout and Code Compilation for Performance
Meet Magento Sweden - Magento 2 Layout and Code Compilation for Performance
Ivan Chepurnyi25.7K views
Data20161007 by capegmail
Data20161007Data20161007
Data20161007
capegmail98 views
IndexedDB - Querying and Performance by Parashuram N
IndexedDB - Querying and PerformanceIndexedDB - Querying and Performance
IndexedDB - Querying and Performance
Parashuram N11.9K views
Decoupling the Ulabox.com monolith. From CRUD to DDD by Aleix Vergés
Decoupling the Ulabox.com monolith. From CRUD to DDDDecoupling the Ulabox.com monolith. From CRUD to DDD
Decoupling the Ulabox.com monolith. From CRUD to DDD
Aleix Vergés1.8K views
Using Objects to Organize your jQuery Code by Rebecca Murphey
Using Objects to Organize your jQuery CodeUsing Objects to Organize your jQuery Code
Using Objects to Organize your jQuery Code
Rebecca Murphey20.5K views
Modules and injector by Eyal Vardi
Modules and injectorModules and injector
Modules and injector
Eyal Vardi7.7K views
Performance Optimization In Angular 2 by Eyal Vardi
Performance Optimization In Angular 2Performance Optimization In Angular 2
Performance Optimization In Angular 2
Eyal Vardi1.7K views
Django Templates by Willy Liu
Django TemplatesDjango Templates
Django Templates
Willy Liu1.2K views

Similar to Gutenberg sous le capot, modules réutilisables

Introduction to backbone presentation by
Introduction to backbone presentationIntroduction to backbone presentation
Introduction to backbone presentationBrian Hogg
1.2K views44 slides
Building complex User Interfaces with Sitecore and React by
Building complex User Interfaces with Sitecore and ReactBuilding complex User Interfaces with Sitecore and React
Building complex User Interfaces with Sitecore and ReactJonne Kats
204 views17 slides
EWD 3 Training Course Part 39: Building a React.js application with QEWD, Part 3 by
EWD 3 Training Course Part 39: Building a React.js application with QEWD, Part 3EWD 3 Training Course Part 39: Building a React.js application with QEWD, Part 3
EWD 3 Training Course Part 39: Building a React.js application with QEWD, Part 3Rob Tweed
627 views19 slides
Introduction to VueJS & Vuex by
Introduction to VueJS & VuexIntroduction to VueJS & Vuex
Introduction to VueJS & VuexBernd Alter
859 views26 slides
Big Data for each one of us by
Big Data for each one of usBig Data for each one of us
Big Data for each one of usOSCON Byrum
2.1K views41 slides
React outbox by
React outboxReact outbox
React outboxAngela Lehru
104 views23 slides

Similar to Gutenberg sous le capot, modules réutilisables(20)

Introduction to backbone presentation by Brian Hogg
Introduction to backbone presentationIntroduction to backbone presentation
Introduction to backbone presentation
Brian Hogg1.2K views
Building complex User Interfaces with Sitecore and React by Jonne Kats
Building complex User Interfaces with Sitecore and ReactBuilding complex User Interfaces with Sitecore and React
Building complex User Interfaces with Sitecore and React
Jonne Kats204 views
EWD 3 Training Course Part 39: Building a React.js application with QEWD, Part 3 by Rob Tweed
EWD 3 Training Course Part 39: Building a React.js application with QEWD, Part 3EWD 3 Training Course Part 39: Building a React.js application with QEWD, Part 3
EWD 3 Training Course Part 39: Building a React.js application with QEWD, Part 3
Rob Tweed627 views
Introduction to VueJS & Vuex by Bernd Alter
Introduction to VueJS & VuexIntroduction to VueJS & Vuex
Introduction to VueJS & Vuex
Bernd Alter859 views
Big Data for each one of us by OSCON Byrum
Big Data for each one of usBig Data for each one of us
Big Data for each one of us
OSCON Byrum2.1K views
PHPConf-TW 2012 # Twig by Wake Liu
PHPConf-TW 2012 # TwigPHPConf-TW 2012 # Twig
PHPConf-TW 2012 # Twig
Wake Liu2.3K views
First Steps in Drupal Code Driven Development by Nuvole
First Steps in Drupal Code Driven DevelopmentFirst Steps in Drupal Code Driven Development
First Steps in Drupal Code Driven Development
Nuvole7.5K views
Vue routing tutorial getting started with vue router by Katy Slemon
Vue routing tutorial getting started with vue routerVue routing tutorial getting started with vue router
Vue routing tutorial getting started with vue router
Katy Slemon42 views
Custom gutenberg block development in react by Imran Sayed
Custom gutenberg block development in reactCustom gutenberg block development in react
Custom gutenberg block development in react
Imran Sayed926 views
Django Class-based views (Slovenian) by Luka Zakrajšek
Django Class-based views (Slovenian)Django Class-based views (Slovenian)
Django Class-based views (Slovenian)
Luka Zakrajšek1.1K views
Understanding backbonejs by Nick Lee
Understanding backbonejsUnderstanding backbonejs
Understanding backbonejs
Nick Lee2.6K views
Angular 2 Architecture (Bucharest 26/10/2016) by Eyal Vardi
Angular 2 Architecture (Bucharest 26/10/2016)Angular 2 Architecture (Bucharest 26/10/2016)
Angular 2 Architecture (Bucharest 26/10/2016)
Eyal Vardi4.1K views
Building Universal Web Apps with React ForwardJS 2017 by Elyse Kolker Gordon
Building Universal Web Apps with React ForwardJS 2017Building Universal Web Apps with React ForwardJS 2017
Building Universal Web Apps with React ForwardJS 2017
前端MVC 豆瓣说 by Ting Lv
前端MVC 豆瓣说前端MVC 豆瓣说
前端MVC 豆瓣说
Ting Lv3.7K views
[22]Efficient and Testable MVVM pattern by NAVER Engineering
[22]Efficient and Testable MVVM pattern[22]Efficient and Testable MVVM pattern
[22]Efficient and Testable MVVM pattern
NAVER Engineering1.4K views

Recently uploaded

The Dark Web : Hidden Services by
The Dark Web : Hidden ServicesThe Dark Web : Hidden Services
The Dark Web : Hidden ServicesAnshu Singh
5 views24 slides
Marketing and Community Building in Web3 by
Marketing and Community Building in Web3Marketing and Community Building in Web3
Marketing and Community Building in Web3Federico Ast
14 views64 slides
information by
informationinformation
informationkhelgishekhar
10 views4 slides
How to think like a threat actor for Kubernetes.pptx by
How to think like a threat actor for Kubernetes.pptxHow to think like a threat actor for Kubernetes.pptx
How to think like a threat actor for Kubernetes.pptxLibbySchulze1
5 views33 slides
hamro digital logics.pptx by
hamro digital logics.pptxhamro digital logics.pptx
hamro digital logics.pptxtupeshghimire
9 views36 slides
Affiliate Marketing by
Affiliate MarketingAffiliate Marketing
Affiliate MarketingNavin Dhanuka
17 views30 slides

Recently uploaded(9)

The Dark Web : Hidden Services by Anshu Singh
The Dark Web : Hidden ServicesThe Dark Web : Hidden Services
The Dark Web : Hidden Services
Anshu Singh5 views
Marketing and Community Building in Web3 by Federico Ast
Marketing and Community Building in Web3Marketing and Community Building in Web3
Marketing and Community Building in Web3
Federico Ast14 views
How to think like a threat actor for Kubernetes.pptx by LibbySchulze1
How to think like a threat actor for Kubernetes.pptxHow to think like a threat actor for Kubernetes.pptx
How to think like a threat actor for Kubernetes.pptx
LibbySchulze15 views
ATPMOUSE_융합2조.pptx by kts120898
ATPMOUSE_융합2조.pptxATPMOUSE_융합2조.pptx
ATPMOUSE_융합2조.pptx
kts12089824 views
IETF 118: Starlink Protocol Performance by APNIC
IETF 118: Starlink Protocol PerformanceIETF 118: Starlink Protocol Performance
IETF 118: Starlink Protocol Performance
APNIC394 views
Building trust in our information ecosystem: who do we trust in an emergency by Tina Purnat
Building trust in our information ecosystem: who do we trust in an emergencyBuilding trust in our information ecosystem: who do we trust in an emergency
Building trust in our information ecosystem: who do we trust in an emergency
Tina Purnat109 views

Gutenberg sous le capot, modules réutilisables

  • 1. Riad Benguella @riadbenguella riad.blog Gutenberg sous le capot
  • 4. “ ” MATT MULLENWEG Learn JavaScript Deeply The State of the Word 2015
  • 7. 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
  • 8. 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’ ), );
  • 11. Abstraction on top of React wp_register_script( ‘my-plugin-script’, ‘path/to/my-script’, array( ‘wp-element’ ), ); Ajout de la dépendance
  • 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. 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. 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
  • 15. À retenir wp.element.createElement <=> JSX pour créer des éléments wp.element.render pour afficher un composant.
  • 17. The new Meta Boxes? Un module générique pour étendre l’UI de WordPress
  • 19. const { registerPlugin } = wp.plugins; const { PluginSidebar, PluginMoreMenuItem } = wp.editPost; The new meta boxes
  • 20. The new meta boxes const { registerPlugin } = wp.plugins; const { PluginSidebar, PluginMoreMenuItem } = wp.editPost;
  • 21. 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
  • 22. 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> );
  • 23. The new meta boxes registerPlugin("dropit", { render: DropIt });
  • 25. À 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
  • 27. Reusable UI components Une collection de composants graphiques pour construire son interface
  • 28. 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’ ), );
  • 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. 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. 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. 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 } ); ); }
  • 34. 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 } ); ); }
  • 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. 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> ); }
  • 38. 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> ); }
  • 40. const { IconButton } = wp.components; class PhotoList extends Component { render() { return ( <div> <form /*… */ /> { this.state.photos.map( photo => ( <Photo key={photo.id} photo={photo} /> ) ) } </div> ); } }
  • 41. class Photo extends Component { onAddPhoto() => {} render() { return ( <div> <img src={this.props.photo.url} /> <IconButton icon=“plus” onClick={ this.onAddPhoto } /> </div> ); } }
  • 42. class Photo extends Component { onAddPhoto() => {} render() { return ( <div> <img src={this.props.photo.url} /> <IconButton icon=“plus” onClick={ this.onAddPhoto } /> </div> ); } }
  • 43. class Photo extends Component { onAddPhoto() => {} render() { return ( <div> <img src={this.props.photo.url} /> <IconButton icon=“plus” onClick={ this.onAddPhoto } /> </div> ); } }
  • 45. À 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
  • 47. Chaque module WP peut mettre des données à disposition des plugins.
  • 49. 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
  • 50. 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
  • 51. 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
  • 52. 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
  • 53. 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
  • 54. 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
  • 55. À 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
  • 58. 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> ); }
  • 59. 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> ); }
  • 60. À 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
  • 62. À 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)
  • 66. Join the conversation: #core-editor, mercredi 16:00 #core-js, mardi 15:00
  • 67. Et notre plugin alors? wordpress.org/plugins/dropit
  • 68. Venez me voir, parlons Gutenberg