Skip to content

Instantly share code, notes, and snippets.

@igorbenic
Last active January 8, 2021 10:44
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save igorbenic/e3e2eaf926405fe9551683a1f70b344b to your computer and use it in GitHub Desktop.
Save igorbenic/e3e2eaf926405fe9551683a1f70b344b to your computer and use it in GitHub Desktop.
Powering the WordPress Search with React and REST API | https://www.ibenic.com/wordpress-react-search
{
"name": "wordpress-search-react",
"version": "1.0.0",
"description": "Powering WordPress Search with React and REST API",
"main": "assets/js/public.js",
"scripts": {
"build": "webpack",
"watch": "webpack --watch",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"babel-core": "^6.26.0",
"babel-loader": "^7.1.2",
"babel-preset-env": "^1.6.1",
"babel-preset-react": "^6.24.1",
"react": "^16.2.0",
"react-dom": "^16.2.0",
"webpack": "^3.10.0"
}
}
<?php
/**
* Plugin Name: Powering WordPress Search with React and REST API
* Description: Replacing the search with React
* Plugin URI: https://www.ibenic.com/wordpress-react-search
*/
if( ! defined( 'ABSPATH' ) ) {
return;
}
add_action( 'wp_enqueue_scripts', 'wp_react_rest_api_scripts' );
/**
* Enqueueing the script
*/
function wp_react_rest_api_scripts() {
wp_enqueue_script( 'react-rest-js', plugin_dir_url( __FILE__ ) . 'assets/js/public.min.js', array( 'jquery' ), '', true );
wp_localize_script( 'react-rest-js', 'wp_react_js', array(
// Adding the post search REST URL
'rest_search_posts' => rest_url( 'wp/v2/posts?search=%s' )));
}
import React from 'react';
import ReactDOM from 'react-dom';
const searchFields = document.getElementsByClassName('search-form');
if( searchFields.length ) {
for( let i=0; i < searchFields.length; i++ ) {
// We will replace each search form .search-form on the page
}
}
import React from 'react';
import ReactDOM from 'react-dom';
import SearchForm from './components/searchForm';
const searchFormElement = <SearchForm />;
const searchFields = document.getElementsByClassName('search-form');
if( searchFields.length ) {
for( let i=0; i < searchFields.length; i++ ) {
console.log( searchFields[ i ]);
ReactDOM.render(
searchFormElement,
searchFields[ i ]
);
}
}
import React from 'react';
export default class SearchForm extends React.Component {
constructor(props) {
super(props);
this.getResults = this.getResults.bind(this);
this.state = {
results : [], // Results from search
loading: false, // Are we still loading the previous results?
searched: false // Are we actually even searching (any words in input)?
};
}
getResults(e) {
if( this.state.loading ) {
return;
}
}
render() {
return (
<div className="search-form-input">
<input className="search-input" type="text" onKeyUp={this.getResults} />
</div>
)
}
}
export default class SearchForm extends React.Component {
// .. code
getResults(e) {
if( this.state.loading ) {
return;
}
// Get the input value
const search = e.target.value;
// At least 3 letters
if( search && search.length > 2 ) {
// We are loading and searching
this.setState({ loading: true, searched: true });
// Let's change the %s into the search param of our REST URL.
let url = wp_react_js.rest_search_posts.replace( '%s', search );
let json = fetch(url)
.then(response => { return response.json()})
.then(results => {this.setState({results: results, loading:false});}); // We got the results, we are not loading anymore
} else {
// No input, so we are not searching.
this.setState({results: [], searched: false });
}
}
// ...
}
import React from 'react';
import SearchResults from './searchResults';
export default class SearchForm extends React.Component {
// ...
render() {
return (
<div className="search-form-input">
<input className="search-input" type="text" onKeyUp={this.getResults} />
<SearchResults searched={this.state.searched} loading={this.state.loading} results={this.state.results}/>
</div>
)
}
}
import React from 'react';
export default class SearchResult extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<li>
<a href={this.props.result.link}>{this.props.result.title.rendered}</a>
</li>
)
}
}
import React from 'react';
import SearchResult from './SearchResult';
export default class SearchResults extends React.Component {
constructor(props) {
super(props);
}
render() {
let results = '';
if( this.props.loading ) {
// We are loading the results.
results = <p>Loading</p>;
} else if( this.props.results.length > 0 ) {
// Results loaded and there are some of it.
const _results = this.props.results.map( result => {
return(<SearchResult key={result.id} result={result}/>); // SearchResult is a new component.
});
results = <ul>{_results}</ul>;
} else if( this.props.searched ) {
// Results loaded, but none found.
results = <p>Nothing Found</p>;
}
return (
<div>{results}</div>
)
}
}
const path = require('path');
module.exports = {
entry: './assets/js/public.js',
externals: {
jquery: "jQuery"
},
output: {
filename: 'public.min.js',
path: path.resolve( __dirname, 'assets/js' )
},
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['babel-preset-env', 'babel-preset-react']
}
}
}
]
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment