M é m o - l a b .
WordPress propose l’avantage de livrer une zone d’administration complète et installable en quelques secondes. dans la majorité des cas, la partie front end est dévelppée en php selon les « règles WordPress ». Il est pourtant possible de n’utiliser WordPress que pour bénéficier de sa zone d’administration et de confier l’affichage à une autre application. Dans notre cas, l’affichage sera réalisé en javascript en utilisant le framework front-end React. Cela est réalisable grâce à l’API REST WordPress. Pour rappel une api (Application Programming Interfaces) est une interface qui permet à des applications de s’échanger des informations, des services ou des données.
Pour résumer, tous les contenus sont saisis depuis l’administration WordPress et sont affichés en React grâce à l’API REST WordPress.
Après avoir installé WordPress (chapitre Installer WordPress), se positionner dans une console (cmder, invite de commande…) sur le dossier themes (<projet>/wp-content/themes) et saisir la commande create-react-app react-app
. Un projet React clé en main est alors disponible sous le dossier react-app (<projet>/wp-content/themes/react-app). Un router étant également nécessaire, nous installons cette dépendance via npm (gestionnaire de paquets de nodejs) en saisissant en console sur le dossier react-app, la commande npm install react-router-dom --save
. Pour admirer notre site web, lancer en console, sur le dossier react-app, le serveur intégré en saisissant la commande yarn start
. Un onglet du navigateur s’ouvre automatiquement sous l’url http://localhost/3000.
L’API REST WordPress est disponible depuis l’url http://localhost/<projet>/wp-json/wp/v2. Elle liste les url qui pourront être utilisées par l’application front-end (React) pour récupérer les données entrées en back-office. Comme pour la plupart des APIs, les données transmises par l’API WordPress sont au format JSON. React reçoit donc des données au format json.
Dans notre projet react-app, nous modifions le fichier App.js
qui est le point d’entrée de notre site et nous y intégrons le routage. Homepage.js
affiche la page d’accueil, Articles.js
affiche une liste des articles et le click sur le titre affiche l’article dans la page Article.js
. Les 3 fichiers Homepage.js, Articles.js et Article.js sont placés dans le dossier react-app/src/component. Le fichier de style app.css est placé dans le dossier react-app/src/dist/css/app.css.
Rqe : Si l’on souhaite ajouter des classes dans les balises html des fichiers js, il faut utiliser l’attribut className et non class.
La compréhension par le code
App.js
import React, {Component} from 'react';
// Intégration du router
import {Link, Route, Switch, BrowserRouter} from 'react-router-dom';
// Importation des fichiers Homepage.js, Articles.js et Article.js
import Homepage from './component/Homepage';
import Articles from './component/Articles';
import Article from './component/Article';
// Importation du fichier app.css
import './dist/css/app.css';
class App extends Component {
render () {
return (
// Menu de navigation
<BrowserRouter>
<nav>
<ul className="">
<li className="">
<Link className="" to="/">Accueil</Link>
</li>
<li className="">
<Link className="" to="/articles">Articles</Link>
</li>
</ul>
</nav>
// Système de routing
<Switch>
<Route path="/" exact component={Homepage} />
<Route path="/articles" component={Articles} />
// id de l'article que l'on récupère dans
// le fichier Article.js
<Route path="/article/:id" component={Article} />
</Switch>
</BrowserRouter>
)
}
}
export default App;
Homepage.js
import React, {Component} from 'react';
class Homepage extends Component
{
render() {
return (
<div>
<p>Lorem ipsum dolor sit amet.</p>
</div>
)
}
}
export default Homepage;
Articles.js
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
class Articles extends Component
{
constructor() {
// super() permet d'appeler le constructeur de la classe
// parente (React.Component) afin de pouvoir utiliser this
super()
this.state = {
articles: null,
// loading est un booléen représantant l'état de
// chargement des articles
loading: true
}
this.getArticles()
}
getArticles() {
// Récupération des articles via l'API REST WordPress
let url = 'http://localhost/wp_tryreact/wp-json/wp/v2/posts'
fetch(url)
.then(response => response.json())
.then((response) => {
this.setState({
articles: response,
loading: false
})
})
}
displayArticles() {
// map produit une liste
return this.state.articles.map((article, key) => {
return(
// Chaque élément d'une liste doit posséder une clé unique
<div key={key}>
<h3>
// article.id retourne l'id de l'article
<Link className="" to={'/article/' +article.id} dangerouslySetInnerHTML={{__html: article.title.rendered}}></Link>
</h3>
<p dangerouslySetInnerHTML={{__html: article.content.rendered}}></p>
</div>
)
})
}
render() {
return (
<div>
<h3>Liste des articles</h3>
// Affichage de la liste si la variable loading est à true
{this.state.loading ? <div>Loading...</div> : this.displayArticles()}
</div>
)
}
}
export default Articles;
Article.js
import React, { Component } from 'react';
class Article extends Component
{
constructor(props) {
// super() permet d'appeler le constructeur de la classe
// parente (React.Component) afin de pouvoir utiliser this
super(props)
// id de l'article passé en paramètre de la route (cf App.js)
this.id = props.match.params.id
this.state = {
article: null,
loading: true
}
this.getArticle()
}
getArticle() {
// Récupération de l'article par son id via l'API REST WordPress
let url = 'http://localhost/wp_tryreact/wp-json/wp/v2/posts/' +this.id
fetch(url)
.then(response => response.json())
.then((response) => {
this.setState({
article: response,
loading: false
})
})
}
displayArticle() {
return(
<div>
<h3 dangerouslySetInnerHTML={{__html: this.state.article.title.rendered}}></h3>
<p dangerouslySetInnerHTML={{__html: this.state.article.content.rendered}}></p>
</div>
)
}
render() {
return (
<div>
// Affichage de l'article si la variable loading est à true
{this.state.loading ? <div>Loading...</div> : this.displayArticle()}
</div>
)
}
}
export default Article;
Remarque concernant l’API REST de WordPress. Il est possible de créer sa propre api en utilisant l’action rest_api-init que l’on peut placer dans le fichier functions.php. Il faut alors définir L’url appelée depuis React, personnaliser la requête WordPress et retourner les résultats au format json.
functions.php
<?php
// API personnalisée récupérant les articles
function api_posts() {
// Requête WordPresss récupérant les articles
$posts = get_posts([
'post_type' => 'post',
'posts_per_page'=> -1,
'numberposts'=> -1
]);
// Résultat retourné au format json
return $posts;
}
// API personnalisée récupérant un article par son id
function api_post($data) {
// Requête WordPresss récupérant un article
$post = get_post($data['id']);
// Résultat retourné au format json
return $post;
}
add_action('rest_api_init', function () {
register_rest_route('api', '/posts', [
'methods' => 'GET',
'callback' => 'api_posts'
]);
register_rest_route('api', '/post/(?P<id>[\d]+)', [
'methods' => 'GET',
'callback' => 'api_post',
'args' => [
'id'
]
]);
});
Articles.js
// la ligne d'appel de l'url devient :
let url = 'http://localhost/wp_tryreact/wp-json/api/posts'
// la fonction displayArticles() devient :
displayArticles() {
return this.state.articles.map((article) => {
return(
<div>
<h3>
<Link className="" to={'/article/' +article.ID} dangerouslySetInnerHTML={{ __html: article.post_title}}></Link>
</h3>
<p dangerouslySetInnerHTML={{__html: article.post_content}}></p>
</div>
)
})
}
Article.js
// la ligne d'appel de l'url devient :
let url = 'http://localhost/wp_tryreact/wp-json/api/post/' +this.id
// la fonction displayArticle() devient :
displayArticle() {
return(
<div>
<h3 dangerouslySetInnerHTML={{__html: this.state.article.post_title}}></h3>
<p dangerouslySetInnerHTML={{__html: this.state.article.post_content}}></p>
</div>
)
}