I am building a Ecommerce Wordpress/Woocommerce Theme using React.js. I am using the npm package:
create-react-wptheme
This package renders the react app directly inside of the index.php of the wordpress theme.
I am unsure how to access the wordpress api endpoints inside of react.js components. I have created the templates for the site using jsx, and need to access the api Endpoints to render dynamic content. I can access the points using http requests to the external api, but I need to be able to access the full api inside of the react-wp-theme.
From what I understand I need to use the backbone.js api client to access the wp rest-api using react.
Or do i possibly need a npm package to hook this up.
How can I make the api available inside of my app.js and components?
I want to make a basic GET request to fetch the posts object, but I do not know how to import the wp Rest-API into react.
Here is a post page where I am trying to fetch a post. It brings up an error. Here is the page:
import React from "react";
class Post extends React.Component {
render() {
let wpPosts = new window.wp.api.collections.Posts();
wpPosts.fetch({ data: { per_page: 2 } }).done(posts => {
posts.forEach(post => {
console.log(post.title.rendered);
});
return (
<div className="container indigo lighten-4">
<div className="container flow-text py-5 mt-5">
<h1>Title</h1>
<p>
content
</p>
</div>
</div>
);
}
}
export default Post;
This Page Does not display here is the error from the console.
Post.js:6 Uncaught TypeError: Cannot read property 'api' of undefined
at Post.render (Post.js:6)
at finishClassComponent (react-dom.development.js:15141)
at updateClassComponent (react-dom.development.js:15096)
at beginWork (react-dom.development.js:15980)
at performUnitOfWork (react-dom.development.js:19102)
at workLoop (react-dom.development.js:19143)
at HTMLUnknownElement.callCallback (react-dom.development.js:147)
at Object.invokeGuardedCallbackDev (react-dom.development.js:196)
at invokeGuardedCallback (react-dom.development.js:250)
at replayUnitOfWork (react-dom.development.js:18350)
render @ Post.js:6
finishClassComponent @ react-dom.development.js:15141
updateClassComponent @ react-dom.development.js:15096
beginWork @ react-dom.development.js:15980
performUnitOfWork @ react-dom.development.js:19102
workLoop @ react-dom.development.js:19143
callCallback @ react-dom.development.js:147
invokeGuardedCallbackDev @ react-dom.development.js:196
invokeGuardedCallback @ react-dom.development.js:250
replayUnitOfWork @ react-dom.development.js:18350
renderRoot @ react-dom.development.js:19261
performWorkOnRoot @ react-dom.development.js:20165
performWork @ react-dom.development.js:20075
performSyncWork @ react-dom.development.js:20049
requestWork @ react-dom.development.js:19904
scheduleWork @ react-dom.development.js:19711
scheduleRootUpdate @ react-dom.development.js:20415
updateContainerAtExpirationTime @ react-dom.development.js:20441
updateContainer @ react-dom.development.js:20509
push../node_modules/react-dom/cjs/react-dom.development.js.ReactRoot.render @ react-dom.development.js:20820
(anonymous) @ react-dom.development.js:20974
unbatchedUpdates @ react-dom.development.js:20292
legacyRenderSubtreeIntoContainer @ react-dom.development.js:20970
render @ react-dom.development.js:21037
./src/index.js @ index.js:6
__webpack_require__ @ bootstrap:78
0 @ serviceWorker.js:135
__webpack_require__ @ bootstrap:78
checkDeferredModules @ bootstrap:45
webpackJsonpCallback @ bootstrap:32
(anonymous) @ main.chunk.js:1
react-dom.development.js:16764 The above error occurred in the <Post> component:
in Post (created by Route)
in Route (at Routes.js:29)
in Switch (at Routes.js:20)
in Routes (at App.js:18)
in div (at App.js:16)
in Router (created by BrowserRouter)
in BrowserRouter (at App.js:15)
in App (at src/index.js:6)
Consider adding an error boundary to your tree to customize error handling behavior.
Visit to learn more about error boundaries.
logCapturedError @ react-dom.development.js:16764
logError @ react-dom.development.js:16800
update.callback @ react-dom.development.js:17814
callCallback @ react-dom.development.js:11743
commitUpdateEffects @ react-dom.development.js:11783
commitUpdateQueue @ react-dom.development.js:11773
commitLifeCycles @ react-dom.development.js:17055
commitAllLifeCycles @ react-dom.development.js:18512
callCallback @ react-dom.development.js:147
invokeGuardedCallbackDev @ react-dom.development.js:196
invokeGuardedCallback @ react-dom.development.js:250
commitRoot @ react-dom.development.js:18717
completeRoot @ react-dom.development.js:20247
performWorkOnRoot @ react-dom.development.js:20170
performWork @ react-dom.development.js:20075
performSyncWork @ react-dom.development.js:20049
requestWork @ react-dom.development.js:19904
scheduleWork @ react-dom.development.js:19711
scheduleRootUpdate @ react-dom.development.js:20415
updateContainerAtExpirationTime @ react-dom.development.js:20441
updateContainer @ react-dom.development.js:20509
push../node_modules/react-dom/cjs/react-dom.development.js.ReactRoot.render @ react-dom.development.js:20820
(anonymous) @ react-dom.development.js:20974
unbatchedUpdates @ react-dom.development.js:20292
legacyRenderSubtreeIntoContainer @ react-dom.development.js:20970
render @ react-dom.development.js:21037
./src/index.js @ index.js:6
__webpack_require__ @ bootstrap:78
0 @ serviceWorker.js:135
__webpack_require__ @ bootstrap:78
checkDeferredModules @ bootstrap:45
webpackJsonpCallback @ bootstrap:32
(anonymous) @ main.chunk.js:1
react-dom.development.js:20135 Uncaught TypeError: Cannot read property 'api' of undefined
at Post.render (Post.js:6)
at finishClassComponent (react-dom.development.js:15141)
at updateClassComponent (react-dom.development.js:15096)
at beginWork (react-dom.development.js:15980)
at performUnitOfWork (react-dom.development.js:19102)
at workLoop (react-dom.development.js:19143)
at renderRoot (react-dom.development.js:19228)
at performWorkOnRoot (react-dom.development.js:20165)
at performWork (react-dom.development.js:20075)
at performSyncWork (react-dom.development.js:20049)
Here is my functions.php that I created to access the api.
<?php
function my_theme_scripts() {
// Enqueue the Backbone JavaScript Client.
wp_enqueue_script( 'wp-api' );
}
add_action( 'wp_enqueue_scripts', 'my_theme_scripts' );
?>
Here is My index.php
<?php
$TEMPLATE_PATH = parse_url(get_template_directory_uri(), PHP_URL_PATH);
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
<!-- Material Icons -->
<link
href="+Icons"
rel="stylesheet"
/>
<!-- Font Awesome -->
<link
rel="stylesheet"
href=".6.3/css/all.css"
integrity="sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/"
crossorigin="anonymous"
/>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<link rel="manifest" href="<?php echo $TEMPLATE_PATH; ?>/manifest.json">
<?php wp_head(); ?>
<title>React WordPress Theme</title>
</head>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<div id="root"></div>
</body>
<?php wp_footer(); ?>
</html>
Here is my App.js
import React, { Component } from "react";
import "./scss/App.scss";
import "./scss/pbml.scss";
import Headers from "./routers/Headers";
import Footer from "./components/footer/Footer";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import "materialize-css/dist/css/materialize.min.css";
import Routes from "./routers/Routes";
class App extends Component {
render() {
return (
<Router>
<div className="cosmos">
<Headers />
<Routes />
<Footer />
</div>
</Router>
);
}
}
export default App;
And Here is my index.js that just points the root to my app.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import * as serviceWorker from "./serviceWorker";
ReactDOM.render(<App />, document.getElementById("root"));
I am building a Ecommerce Wordpress/Woocommerce Theme using React.js. I am using the npm package:
create-react-wptheme
This package renders the react app directly inside of the index.php of the wordpress theme.
I am unsure how to access the wordpress api endpoints inside of react.js components. I have created the templates for the site using jsx, and need to access the api Endpoints to render dynamic content. I can access the points using http requests to the external api, but I need to be able to access the full api inside of the react-wp-theme.
From what I understand I need to use the backbone.js api client to access the wp rest-api using react.
Or do i possibly need a npm package to hook this up.
How can I make the api available inside of my app.js and components?
I want to make a basic GET request to fetch the posts object, but I do not know how to import the wp Rest-API into react.
Here is a post page where I am trying to fetch a post. It brings up an error. Here is the page:
import React from "react";
class Post extends React.Component {
render() {
let wpPosts = new window.wp.api.collections.Posts();
wpPosts.fetch({ data: { per_page: 2 } }).done(posts => {
posts.forEach(post => {
console.log(post.title.rendered);
});
return (
<div className="container indigo lighten-4">
<div className="container flow-text py-5 mt-5">
<h1>Title</h1>
<p>
content
</p>
</div>
</div>
);
}
}
export default Post;
This Page Does not display here is the error from the console.
Post.js:6 Uncaught TypeError: Cannot read property 'api' of undefined
at Post.render (Post.js:6)
at finishClassComponent (react-dom.development.js:15141)
at updateClassComponent (react-dom.development.js:15096)
at beginWork (react-dom.development.js:15980)
at performUnitOfWork (react-dom.development.js:19102)
at workLoop (react-dom.development.js:19143)
at HTMLUnknownElement.callCallback (react-dom.development.js:147)
at Object.invokeGuardedCallbackDev (react-dom.development.js:196)
at invokeGuardedCallback (react-dom.development.js:250)
at replayUnitOfWork (react-dom.development.js:18350)
render @ Post.js:6
finishClassComponent @ react-dom.development.js:15141
updateClassComponent @ react-dom.development.js:15096
beginWork @ react-dom.development.js:15980
performUnitOfWork @ react-dom.development.js:19102
workLoop @ react-dom.development.js:19143
callCallback @ react-dom.development.js:147
invokeGuardedCallbackDev @ react-dom.development.js:196
invokeGuardedCallback @ react-dom.development.js:250
replayUnitOfWork @ react-dom.development.js:18350
renderRoot @ react-dom.development.js:19261
performWorkOnRoot @ react-dom.development.js:20165
performWork @ react-dom.development.js:20075
performSyncWork @ react-dom.development.js:20049
requestWork @ react-dom.development.js:19904
scheduleWork @ react-dom.development.js:19711
scheduleRootUpdate @ react-dom.development.js:20415
updateContainerAtExpirationTime @ react-dom.development.js:20441
updateContainer @ react-dom.development.js:20509
push../node_modules/react-dom/cjs/react-dom.development.js.ReactRoot.render @ react-dom.development.js:20820
(anonymous) @ react-dom.development.js:20974
unbatchedUpdates @ react-dom.development.js:20292
legacyRenderSubtreeIntoContainer @ react-dom.development.js:20970
render @ react-dom.development.js:21037
./src/index.js @ index.js:6
__webpack_require__ @ bootstrap:78
0 @ serviceWorker.js:135
__webpack_require__ @ bootstrap:78
checkDeferredModules @ bootstrap:45
webpackJsonpCallback @ bootstrap:32
(anonymous) @ main.chunk.js:1
react-dom.development.js:16764 The above error occurred in the <Post> component:
in Post (created by Route)
in Route (at Routes.js:29)
in Switch (at Routes.js:20)
in Routes (at App.js:18)
in div (at App.js:16)
in Router (created by BrowserRouter)
in BrowserRouter (at App.js:15)
in App (at src/index.js:6)
Consider adding an error boundary to your tree to customize error handling behavior.
Visit https://fb.me/react-error-boundaries to learn more about error boundaries.
logCapturedError @ react-dom.development.js:16764
logError @ react-dom.development.js:16800
update.callback @ react-dom.development.js:17814
callCallback @ react-dom.development.js:11743
commitUpdateEffects @ react-dom.development.js:11783
commitUpdateQueue @ react-dom.development.js:11773
commitLifeCycles @ react-dom.development.js:17055
commitAllLifeCycles @ react-dom.development.js:18512
callCallback @ react-dom.development.js:147
invokeGuardedCallbackDev @ react-dom.development.js:196
invokeGuardedCallback @ react-dom.development.js:250
commitRoot @ react-dom.development.js:18717
completeRoot @ react-dom.development.js:20247
performWorkOnRoot @ react-dom.development.js:20170
performWork @ react-dom.development.js:20075
performSyncWork @ react-dom.development.js:20049
requestWork @ react-dom.development.js:19904
scheduleWork @ react-dom.development.js:19711
scheduleRootUpdate @ react-dom.development.js:20415
updateContainerAtExpirationTime @ react-dom.development.js:20441
updateContainer @ react-dom.development.js:20509
push../node_modules/react-dom/cjs/react-dom.development.js.ReactRoot.render @ react-dom.development.js:20820
(anonymous) @ react-dom.development.js:20974
unbatchedUpdates @ react-dom.development.js:20292
legacyRenderSubtreeIntoContainer @ react-dom.development.js:20970
render @ react-dom.development.js:21037
./src/index.js @ index.js:6
__webpack_require__ @ bootstrap:78
0 @ serviceWorker.js:135
__webpack_require__ @ bootstrap:78
checkDeferredModules @ bootstrap:45
webpackJsonpCallback @ bootstrap:32
(anonymous) @ main.chunk.js:1
react-dom.development.js:20135 Uncaught TypeError: Cannot read property 'api' of undefined
at Post.render (Post.js:6)
at finishClassComponent (react-dom.development.js:15141)
at updateClassComponent (react-dom.development.js:15096)
at beginWork (react-dom.development.js:15980)
at performUnitOfWork (react-dom.development.js:19102)
at workLoop (react-dom.development.js:19143)
at renderRoot (react-dom.development.js:19228)
at performWorkOnRoot (react-dom.development.js:20165)
at performWork (react-dom.development.js:20075)
at performSyncWork (react-dom.development.js:20049)
Here is my functions.php that I created to access the api.
<?php
function my_theme_scripts() {
// Enqueue the Backbone JavaScript Client.
wp_enqueue_script( 'wp-api' );
}
add_action( 'wp_enqueue_scripts', 'my_theme_scripts' );
?>
Here is My index.php
<?php
$TEMPLATE_PATH = parse_url(get_template_directory_uri(), PHP_URL_PATH);
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
<!-- Material Icons -->
<link
href="https://fonts.googleapis/icon?family=Material+Icons"
rel="stylesheet"
/>
<!-- Font Awesome -->
<link
rel="stylesheet"
href="https://use.fontawesome/releases/v5.6.3/css/all.css"
integrity="sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/"
crossorigin="anonymous"
/>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<link rel="manifest" href="<?php echo $TEMPLATE_PATH; ?>/manifest.json">
<?php wp_head(); ?>
<title>React WordPress Theme</title>
</head>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<div id="root"></div>
</body>
<?php wp_footer(); ?>
</html>
Here is my App.js
import React, { Component } from "react";
import "./scss/App.scss";
import "./scss/pbml.scss";
import Headers from "./routers/Headers";
import Footer from "./components/footer/Footer";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import "materialize-css/dist/css/materialize.min.css";
import Routes from "./routers/Routes";
class App extends Component {
render() {
return (
<Router>
<div className="cosmos">
<Headers />
<Routes />
<Footer />
</div>
</Router>
);
}
}
export default App;
And Here is my index.js that just points the root to my app.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import * as serviceWorker from "./serviceWorker";
ReactDOM.render(<App />, document.getElementById("root"));
Share
Improve this question
edited Feb 7, 2019 at 5:25
Toni Wheeler
asked Feb 6, 2019 at 1:22
Toni WheelerToni Wheeler
33 bronze badges
10
|
Show 5 more comments
1 Answer
Reset to default 1I can access the points using http requests to the external api, but I need to be able to access the full api inside of the react-wp-theme.
You could use either the wp-api
script / Backbone JavaScript client library or one of the other client libraries listed here such as the node-wpapi
library.
Using the wp-api
script
Enqueue the script:
wp_enqueue_script( 'wp-api' );
In
index.php
, make sure<?php wp_head(); ?>
is added in the documenthead
, and<?php wp_footer(); ?>
in thebody
.
And then in your React components, access the client via window.wp.api
instead of just wp.api
:
const postsCollection = new window.wp.api.collections.Posts(); // like this
//const postsCollection = new wp.api.collections.Posts(); // not this
Here's an example React Component which uses the Posts
collection to retrieve one post: (the markup is based on your Post
component)
import React from "react";
class Post extends React.Component {
constructor(props) {
super(props);
this.state = {
error: null,
isLoaded: false,
item: {}
};
}
componentDidMount() {
// Instantiates the collection.
const postsCollection = new window.wp.api.collections.Posts();
// Retrieves one post.
postsCollection.fetch({ data: { per_page: 1 } })
.done(posts => {
this.setState({
isLoaded: true,
item: posts[0]
});
})
.error((xhr, status, error) => {
this.setState({
isLoaded: true,
error
});
});
}
render() {
const { error, isLoaded, item } = this.state;
if (error || item.errors) {
return <div>Error: {error || 'API error...'}</div>;
} else if (! isLoaded) {
return <div>Loading...</div>;
} else {
return (
<div className="container indigo lighten-4">
<div className="container flow-text py-5 mt-5">
<h3>{item.title.rendered}</h3>
<p>{item.excerpt.rendered}</p>
</div>
</div>
);
}
}
}
export default Post;
Tried and tested working, and the code is based on the official example.
Using the node-wpapi
library
You can refer to the documentation on installing the library and using it.
But here's the above Post
component, adapted to using the node-wpapi
library: (the ...
means nothing changed)
import React from "react";
const WPAPI = require('wpapi');
const wp = new WPAPI({
endpoint: 'http://example/wp-json'
});
class Post extends React.Component {
constructor(props) {
...
}
componentDidMount() {
// Retrieves one post.
wp.posts().perPage(1)
.then(posts => {
this.setState({
isLoaded: true,
item: posts[0]
});
})
.catch(err => {
this.setState({
isLoaded: true,
error: err.message
});
});
}
render() {
...
}
}
export default Post;
The Full Code
You can check my files here.
wp_enqueue_scripts
hook - e.g. Infunctions.php
, doadd_action( 'wp_enqueue_scripts', function(){ wp_enqueue_script( 'wp-api' ); } )
. – Sally CJ Commented Feb 6, 2019 at 3:49wp_head();
in your template (index.php
), so you could put it there - before</head>
, or try addingwp_print_scripts( 'wp-api' );
before</body>
.. – Sally CJ Commented Feb 6, 2019 at 4:04