Headless WordPress – идея, которая используется все активнее в среде разработчиков. Я постараюсь раскрыть несколько тем, связанных с этим подходом. В частности, я покажу, как реализовать вход в приложение с помощью JWT.
Мы создадим простое приложение, которое позволит пользователям входить под своим логином. После входа мы выведем пользователю его данные.
Чтобы реализовать вход в приложение с помощью JWT, нам понадобится установить и активировать плагин JWT Authentication for WP REST API.
Подготовка приложения
Давайте создадим наше собственное приложение React с помощью Create React App. Открываем терминал (командную строку) и переходим к каталогу, в которой будет вестись разработка приложения.
Затем используем команду:
npx create-react-app my-app
Здесь вы можете заменить my-app на свое название. Это будет ваш каталог, в котором будет храниться весь код. Я решил назвать каталог headless.
Затем перейдите к этой папке. Запустить приложение можно уже сейчас с помощью команды npm start. Однако давайте сначала установим Gutenberg Components, npm-пакет @wordpress/components. Это позволит нам использовать различные компоненты в своем приложении.
Установить Gutenberg Components можно с помощью команды
npm install @wordpress/components
Поскольку пакет Gutenberg Components не включает в себя классы разметки, мы можем создать свое собственное руководство по CSS-стилям либо использовать существующие стилевые фреймворки, чтобы не тратить на это свое время. Если вы хотите создать приложение, которое будет использоваться в производстве – обязательно подумайте над тем, чтобы создать свою CSS-разметку.
Мы будем использовать Bootstrap 4 для стилей. Установить его можно с помощью команды:
npm install bootstrap
Также нам потребуется процессинг SASS (SCSS), потому нам нужно, чтобы наше приложение могло обрабатывать такие файлы. Для этого используется следующая команда:
npm install node-sass --save
Поскольку мы будем использовать стили Bootstrap и Gutenberg, мы можем удалить App.css и создать App.scss. Поместите следующее внутрь этого нового файла:
@import '~bootstrap/scss/bootstrap.scss'; @import '~@wordpress/components/build-style/style.css';
Теперь он будет компилироваться в файл CSS, который будет включать в себя стили как Boostrap, так и Gutenberg.
Нам нужно будет выполнять запросы POST и GET к нашему сайту WordPress, потому нам понадобится способ реализации этого. Вы можете использовать fetch из API браузера, либо библиотеку. Мы будем использовать библиотеку axios. Она устанавливается с помощью команды
npm install axios
Добавляем логику входа к нашему Headless WordPress
Откройте App.js, чтобы начать добавление логики входа. Мы будем проверять, является ли пользователь залогиненным или нет. Если нет, то мы покажем форму входа. В противном случае будет выводиться консоль.
Давайте скорректируем все импорты в приложении:
import React, { useState, useEffect } from 'react'; import './App.scss'; import '@wordpress/components/build-style/style.css'; import Login from './components/Login'; import Dashboard from './components/Dashboard';
Не беспокойтесь по поводу появляющихся ошибок. Компоненты Dashboard и Login пока что не существуют, потому вы можете получать ошибки компиляции.
Теперь мы можем заменить функцию App на следующее:
function App() { const [login, setLogin] = useState( '' ); const siteURL = 'yoursite_here'; useEffect(() => { const localLogin = localStorage.getItem('login'); // If we have logged in, set it. if ( localLogin ) { setLogin( localLogin ); } }, [login]); return ( <div className="App container"> <h1>Headless WordPress</h1> { login && <Dashboard url={siteURL} token={login} setLogin={setLogin} /> } { ! login && <Login url={siteURL} setLogin={setLogin}/> } </div> ); }
Что мы здесь сделали:
- Мы использовали хуки React useState для глобальной обработки информации по логину
- Мы использовали хуки useEffect для обработки изменений в процессе входа в приложение
- Если мы залогинены, то в таком случае будет выведен компонент Dashboard
- Если мы не вошли в приложение, то тогда будет выведен компонент Login
С помощью useEffect наше приложение будет осуществлять вход нашего пользователя (если токен сохранен).
Мы передаем в оба компонента функцию setLogin, которая управляет глобальным состоянием для информации по входу в систему. Это позволит нам, к примеру, предлагать логаут для пользователей.
Создание компонента Login
Чтобы осуществить процедуру входа в наше приложение Headless WordPress для пользователя, нам нужно передать логин и пароль с первой попытки. Для этого нам нужна отдельная форма. Создадим папку components в папке с приложением и создадим файл Login.js.
Поместим в него следующий код:
import React from 'react'; import { TextControl, Button } from '@wordpress/components'; const axios = require('axios'); class Login extends React.Component { constructor( props ) { super( props ); this.state = { username: '', password: '' } this.handleUsername = this.handleUsername.bind(this); this.handlePassword = this.handlePassword.bind(this); this.handleSubmit = this.handleSubmit.bind(this); } } export default Login;
Мы импортируем Gutenberg-компоненты TextControl и Button, которые мы будем использовать для создания формы входа. У нас также будет еще 3 метода. Эти методы будут использоваться для хранения информации о состоянии входа в приложение, а также о логине пользователя.
Давайте создадим метод render и 2 метода для сохранения информации о состоянии входа. Вы увидите, как мы используем Gutenberg Components.
// ... class Login extends React.Component { // ... handleUsername( username ) { this.setState( { username } ) } handlePassword( password ) { this.setState( { password } ) } render() { return ( <form className="login" method="post"> <TextControl className="form-group" label="Username" value={ this.state.username } onChange={ (value) => this.handleUsername( value ) } /> <TextControl className="form-group" label="Password" type="password" onChange={ (value) => this.handlePassword( value ) } /> <Button isPrimary onClick={this.handleSubmit}>Login</Button> </form> ); } }
Второй TextControl также получает password в качестве типа. Когда какой-либо из элементов управления изменится, он будет использовать соответствующий метод для сохранения информации о состоянии входа.
При нажатии на компонент Button мы будем пытаться войти в систему под пользователем. Давайте создадим этот метод сейчас:
//... class Login extends React.Component { //... handleSubmit( e ) { e.preventDefault(); const _this = this; axios.post( this.props.url + '/wp-json/jwt-auth/v1/token/', { username: this.state.username, password: this.state.password }) .then(function (response) { if ( response.status === 200 ) { const data = response.data; localStorage.setItem( 'login', data.token ); _this.props.setLogin( data.token ); } }) .catch(function (error) { function strip_html_tags(str) { if ((str===null) || (str==='')) return false; else str = str.toString(); return str.replace(/<[^>]*>/g, ''); } alert( strip_html_tags( error.response.data.message ) ); }); } // ... }
Мы публикуем имя пользователя и пароль в REST-маршруте для токена jwt. Если пользователь существует, то нам будет возвращен этот токен. Затем мы внесем токен в локальное хранилище, чтобы мы могли получить его при обновлении.
Если этот REST-маршрут вернет нам какие-либо ошибки, мы отобразим их без HTML-тегов.
Все это позволит нашим пользователям войти в приложение WordPress Headless.
Создание компонента Dashboard
В нашем компоненте Dashboard мы будем выводить информацию о нашем пользователе, чтобы мы знали, что мы получили корректного пользователя.
Создаем файл Dashboard.js внутри каталога components и помещаем в него следующее:
import React from 'react'; const axios = require('axios'); class Dashboard extends React.Component { constructor( props ) { super( props ); this.state = { user: { } }; this.Logout = this.Logout.bind(this); this.getCurrentUser = this.getCurrentUser.bind(this); } } export default Dashboard;
Нам также понадобится здесь axios, поскольку мы будем получать информацию о текущем залогиненном пользователе. Мы хотим получить эту информацию как можно скорее, еще когда компонент монтируется.
// ... class Dashboard extends React.Component { // ... componentDidMount() { this.getCurrentUser(); } getCurrentUser() { const token = this.props.token; const userURI = this.props.url + '/wp-json/wp/v2/users/me'; const _this = this; axios({ method: 'POST', url: userURI, headers: { 'Authorization': 'Bearer ' + token } }).then(function (response) { if ( response.status === 200 ) { const data = response.data; _this.setState( {user:data}); } }) .catch(function (error) { _this.Logout(); }); } }
Мы используем маршрут wp-json/wp/v2/users/me для получения информации о текущем пользователе. Для этого мы передаем заголовок Authorization с нашим Bearer токеном.
Если мы не передадим этот заголовок, то плагин JWT не сможет определить, какой пользователь вошел в приложение.
Давайте теперь выведем информацию о залогиненном пользователе:
// ... class Dashboard extends React.Component { // ... Logout() { localStorage.removeItem('login'); this.props.setLogin(''); } render() { const { nickname, first_name, last_name } = this.state.user; return ( <div className="dashboard"> <button type="button" className="btn btn-danger" onClick={this.Logout}>Logout</button> <div className="jumbotron"> Welcome { nickname } I think your name is { first_name } { last_name} </div> </div> ); } }
У нас есть кнопка логаута, которая также будет использовать переданный метод setLogin. Поскольку мы задали логин в виде пустой строки, приложение выполнит повторный рендеринг и выведет форму входа.
Заключение
Headless WordPress постепенно становится новым стандартом. Вы можете создать такое веб-приложение, которое легко можно будет впоследствии преобразовать в Android или iOS-приложение. Пакет Gutenberg Components значительно экономит время и силы.