├── .gitignore
├── src
├── scripts
│ ├── flux
│ │ ├── alt
│ │ │ └── alt.js
│ │ ├── stores
│ │ │ └── DataStore.js
│ │ └── actions
│ │ │ └── DataActions.js
│ ├── components
│ │ ├── Home.js
│ │ ├── About.js
│ │ ├── Contact.js
│ │ └── Header.js
│ └── index.js
└── index.html
├── README.md
├── package.json
├── webpack.production.js
└── webpack.dev.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
--------------------------------------------------------------------------------
/src/scripts/flux/alt/alt.js:
--------------------------------------------------------------------------------
1 | import Alt from 'alt';
2 | const alt = new Alt();
3 |
4 | export default alt;
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | React with Wordpress API
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/scripts/components/Home.js:
--------------------------------------------------------------------------------
1 | import DataStore from 'flux/stores/DataStore.js'
2 |
3 | class Home extends React.Component {
4 | render() {
5 | let pageData = DataStore.getPageBySlug('home');
6 |
7 | return (
8 |
9 |
Homepage template
10 |
{pageData.title.rendered}
11 |
12 |
13 |
{pageData.acf.text}
14 |
15 | );
16 | }
17 | }
18 |
19 | export default Home;
20 |
--------------------------------------------------------------------------------
/src/scripts/components/About.js:
--------------------------------------------------------------------------------
1 | import DataStore from 'flux/stores/DataStore.js'
2 |
3 | class About extends React.Component {
4 | render() {
5 | let pageData = DataStore.getPageBySlug('about');
6 |
7 | return (
8 |
9 |
About page template
10 |
{pageData.title.rendered}
11 |
12 |
13 |
{pageData.acf.text}
14 |
15 | );
16 | }
17 | }
18 |
19 | export default About;
20 |
--------------------------------------------------------------------------------
/src/scripts/components/Contact.js:
--------------------------------------------------------------------------------
1 | import DataStore from 'flux/stores/DataStore.js'
2 |
3 | class Contact extends React.Component {
4 | render() {
5 | let pageData = DataStore.getPageBySlug('contact');
6 |
7 | return (
8 |
9 |
Contact page template
10 |
{pageData.title.rendered}
11 |
12 |
13 |
{pageData.acf.text}
14 |
15 | );
16 | }
17 | }
18 |
19 | export default Contact;
20 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Wordpress REST API + React JS
2 |
3 | This boilerplate will help you use React JS with Wordpress REST API.
4 | Clone the project and install node packages:
5 |
6 | ```
7 | npm i
8 | ```
9 |
10 | To run the project on localhost:8080:
11 | ```
12 | npm start
13 | ```
14 |
15 | To build the project into /build folder:
16 | ```
17 | npm run build
18 | ```
19 |
20 | You need to have webpack and webpack-dev-server installed globally:
21 | * [`webpack`](http://webpack.github.io/docs/)
22 | ```
23 | npm install -g webpack
24 | ```
25 |
26 | * [`webpack-dev-server`](http://webpack.github.io/docs/webpack-dev-server.html)
27 | ```
28 | npm install -g webpack-dev-server
29 | ```
30 |
31 | Don't forget to update the Worpress installation url in DataActions.js. It's located in src/actions/DataActions.js line 7
32 | ```
33 | class DataActions {
34 | constructor() {
35 | const appUrl = 'http://andreypokrovskiy.com/projects/wp-api'; // Wordpress installation url
36 | }
37 | ```
38 |
--------------------------------------------------------------------------------
/src/scripts/components/Header.js:
--------------------------------------------------------------------------------
1 | import {Link} from 'react-router-dom';
2 | import DataStore from 'flux/stores/DataStore.js'
3 |
4 | class Header extends React.Component {
5 |
6 | render() {
7 | let allPages = DataStore.getAllPages();
8 | allPages = _.sortBy(allPages, [function(page) { return page.menu_order; }]); // Sort pages by order
9 |
10 | return (
11 |
12 | Home
13 |
14 | {allPages.map((page) => {
15 | if(page.slug != 'home'){
16 | return(
17 |
22 | {page.title.rendered}
23 |
24 | )
25 | }
26 | })}
27 |
28 | );
29 | }
30 | }
31 |
32 | export default Header;
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "wp-api-react",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "start": "webpack-dev-server --inline --progress --config webpack.dev.js",
9 | "build": "npm run clean && webpack -p --progress --config webpack.production.js",
10 | "clean": "rimraf ./build/*"
11 | },
12 | "author": "",
13 | "license": "ISC",
14 | "dependencies": {
15 | "alt": "^0.18.6",
16 | "axios": "^0.16.2",
17 | "babel-polyfill": "^6.23.0",
18 | "babel-runtime": "^6.23.0",
19 | "lodash": "^4.17.4",
20 | "react": "^15.5.4",
21 | "react-dom": "^15.5.4",
22 | "react-router-dom": "^4.1.1"
23 | },
24 | "devDependencies": {
25 | "babel-core": "^6.24.1",
26 | "babel-loader": "^7.0.0",
27 | "babel-plugin-transform-runtime": "^6.23.0",
28 | "babel-preset-es2015": "^6.24.1",
29 | "babel-preset-react": "^6.24.1",
30 | "babel-preset-stage-0": "^6.24.1",
31 | "html-webpack-plugin": "^2.28.0",
32 | "react-hot-loader": "^1.3.1",
33 | "rimraf": "^2.6.1",
34 | "webpack": "^2.6.1",
35 | "webpack-dev-server": "^2.4.5"
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/scripts/flux/stores/DataStore.js:
--------------------------------------------------------------------------------
1 | import alt from 'flux/alt/alt.js';
2 | import DataActions from 'flux/actions/DataActions.js';
3 |
4 | class DataStore {
5 | constructor() {
6 | this.data = {};
7 |
8 | this.bindListeners({
9 | // Listen to the getSuccess() in DataActions.js
10 | handleSuccess: DataActions.GET_SUCCESS
11 | });
12 |
13 | this.exportPublicMethods({
14 | getAll: this.getAll,
15 | getAllPages: this.getAllPages,
16 | getAllPosts: this.getAllPosts,
17 | getPageBySlug: this.getPageBySlug
18 | });
19 | }
20 |
21 | // Store data returned by getSuccess() in DataActions.js
22 | handleSuccess(data) {
23 | this.setState({ data });
24 | }
25 |
26 | // Returns all pages and posts
27 | getAll() {
28 | return this.getState().data;
29 | }
30 |
31 | // Returns all Pages
32 | getAllPages() {
33 | return this.getState().data.pages;
34 | }
35 |
36 | // Returns all Posts
37 | getAllPosts() {
38 | return this.getState().data.posts;
39 | }
40 |
41 | // Returns a Page by provided slug
42 | getPageBySlug(slug){
43 | const pages = this.getState().data.pages;
44 | return pages[Object.keys(pages).find((page, i) => {
45 | return pages[page].slug === slug;
46 | })] || {};
47 | }
48 |
49 | }
50 |
51 | export default alt.createStore(DataStore, 'DataStore');
--------------------------------------------------------------------------------
/src/scripts/index.js:
--------------------------------------------------------------------------------
1 | import {render} from 'react-dom';
2 | import DataActions from 'flux/actions/DataActions.js';
3 |
4 | import Home from 'components/Home.js';
5 | import About from 'components/About.js';
6 | import Contact from 'components/Contact.js';
7 | import Header from 'components/Header.js';
8 |
9 | import {
10 | BrowserRouter as Router,
11 | Route,
12 | Redirect,
13 | Switch
14 | } from 'react-router-dom';
15 |
16 |
17 | class AppInitializer {
18 |
19 | templates = {
20 | 'about': About,
21 | 'contact': Contact
22 | }
23 |
24 | buildRoutes(data){
25 | return data.pages.map((page, i) => {
26 | return(
27 |
33 | )
34 | })
35 | }
36 |
37 | run() {
38 | DataActions.getPages((response)=>{
39 | render(
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | {this.buildRoutes(response)}
48 | { return }} />
49 |
50 |
51 |
52 |
53 | , document.getElementById('app')
54 | );
55 | });
56 | }
57 | }
58 |
59 | new AppInitializer().run();
60 |
--------------------------------------------------------------------------------
/src/scripts/flux/actions/DataActions.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | import alt from 'flux/alt/alt.js';
3 |
4 | class DataActions {
5 |
6 | constructor() {
7 | const appUrl = 'http://andreypokrovskiy.com/projects/wp-api-react'; // Wordpress installation url
8 |
9 | this.pagesEndPoint = `${appUrl}/wp-json/wp/v2/pages`; // Endpoint for getting Wordpress Pages
10 | this.postsEndPoint = `${appUrl}/wp-json/wp/v2/posts`; // Endpoint for getting Wordpress Posts
11 | }
12 |
13 | // Method for getting data from the provided end point url
14 | api(endPoint) {
15 | return new Promise((resolve, reject) => {
16 | axios.get(endPoint).then((response) => {
17 | resolve(response.data);
18 | }).catch((error) => {
19 | reject(error);
20 | });
21 | });
22 | }
23 |
24 | // Method for getting Pages data
25 | getPages(cb){
26 | this.api(this.pagesEndPoint).then((response)=>{
27 | this.getPosts(response, cb)
28 | });
29 | return true;
30 | }
31 |
32 | // Method for getting Posts data
33 | getPosts(pages, cb){
34 | this.api(this.postsEndPoint).then((response)=>{
35 | const posts = response
36 | const payload = { pages, posts };
37 |
38 | this.getSuccess(payload); // Pass returned data to the store
39 | cb(payload); // This callback will be used for dynamic rout building
40 | });
41 | return true;
42 | }
43 |
44 | // This returnes an object with Pages and Posts data together
45 | // The Alt Store will listen for this method to fire and will store the returned data
46 | getSuccess(payload){
47 | return payload;
48 | }
49 | }
50 |
51 | export default alt.createActions(DataActions);
--------------------------------------------------------------------------------
/webpack.production.js:
--------------------------------------------------------------------------------
1 | var webpack = require('webpack');
2 | var path = require('path');
3 | var HtmlWebpackPlugin = require('html-webpack-plugin');
4 |
5 | module.exports = {
6 | devtool: 'source-map',
7 | devServer: {
8 | historyApiFallback: true, // This will make the server understand "/some-link" routs instead of "/#/some-link"
9 | },
10 | entry: [
11 | './src/scripts' // This is where Webpack will be looking for the entry index.js file
12 | ],
13 | output: {
14 | path: path.join(__dirname, 'build'), // This is used to specify folder for producion bundle
15 | filename: 'bundle.js', // Filename for production bundle
16 | publicPath: '/'
17 | },
18 | resolve: {
19 | modules: [
20 | 'node_modules',
21 | 'src',
22 | path.resolve(__dirname, 'src/scripts'),
23 | path.resolve(__dirname, 'node_modules')
24 | ], // Folders where Webpack is going to look for files to bundle together
25 | extensions: ['.jsx', '.js'] // Extensions that Webpack is going to expect
26 | },
27 | module: {
28 | // Loaders allow you to preprocess files as you require() or “load” them.
29 | // Loaders are kind of like “tasks” in other build tools, and provide a powerful way to handle frontend build steps.
30 | loaders: [
31 | {
32 | test: /\.jsx?$/, // Here we're going to use JS for react components but including JSX in case this extension is preferable
33 | include: [
34 | path.resolve(__dirname, "src"),
35 | ],
36 | loader: ['react-hot-loader']
37 | },
38 | {
39 | loader: "babel-loader",
40 |
41 | // Skip any files outside of your project's `src` directory
42 | include: [
43 | path.resolve(__dirname, "src"),
44 | ],
45 |
46 | // Only run `.js` and `.jsx` files through Babel
47 | test: /\.jsx?$/,
48 |
49 | // Options to configure babel with
50 | query: {
51 | plugins: ['transform-runtime'],
52 | presets: ['es2015', 'stage-0', 'react'],
53 | }
54 | }
55 | ]
56 | },
57 | plugins: [
58 | new webpack.NoEmitOnErrorsPlugin(), // Webpack will let you know if there are any errors
59 |
60 | // Declare global variables
61 | new webpack.ProvidePlugin({
62 | React: 'react',
63 | ReactDOM: 'react-dom',
64 | _: 'lodash'
65 | }),
66 |
67 | new HtmlWebpackPlugin({
68 | filename: 'index.html',
69 | template: './src/index.html',
70 | hash: true
71 | }),
72 |
73 | new webpack.optimize.UglifyJsPlugin({
74 | compress: {
75 | warnings: false
76 | },
77 | sourceMap: true
78 | }),
79 | ]
80 | }
--------------------------------------------------------------------------------
/webpack.dev.js:
--------------------------------------------------------------------------------
1 | var webpack = require('webpack');
2 | var path = require('path');
3 | var HtmlWebpackPlugin = require('html-webpack-plugin');
4 |
5 | module.exports = {
6 | devtool: 'cheap-module-source-map',
7 | devServer: {
8 | historyApiFallback: true, // This will make the server understand "/some-link" routs instead of "/#/some-link"
9 | },
10 | entry: [
11 | 'babel-polyfill',
12 | 'webpack-dev-server/client?http://127.0.0.1:8080/', // Specify the local server port
13 | 'webpack/hot/only-dev-server', // Enable hot reloading
14 | './src/scripts' // This is where Webpack will be looking for the entry index.js file
15 | ],
16 | output: {
17 | path: path.join(__dirname, 'build'), // This is used to specify folder for producion bundle
18 | filename: 'bundle.js', // Filename for production bundle
19 | publicPath: '/'
20 | },
21 | resolve: {
22 | modules: [
23 | 'node_modules',
24 | 'src',
25 | path.resolve(__dirname, 'src/scripts'),
26 | path.resolve(__dirname, 'node_modules')
27 | ], // Folders where Webpack is going to look for files to bundle together
28 | extensions: ['.jsx', '.js'] // Extensions that Webpack is going to expect
29 | },
30 | module: {
31 | // Loaders allow you to preprocess files as you require() or “load” them.
32 | // Loaders are kind of like “tasks” in other build tools, and provide a powerful way to handle frontend build steps.
33 | loaders: [
34 | {
35 | test: /\.jsx?$/, // Here we're going to use JS for react components but including JSX in case this extension is preferable
36 | include: [
37 | path.resolve(__dirname, "src"),
38 | ],
39 | loader: ['react-hot-loader']
40 | },
41 | {
42 | loader: "babel-loader",
43 |
44 | // Skip any files outside of your project's `src` directory
45 | include: [
46 | path.resolve(__dirname, "src"),
47 | ],
48 |
49 | // Only run `.js` and `.jsx` files through Babel
50 | test: /\.jsx?$/,
51 |
52 | // Options to configure babel with
53 | query: {
54 | plugins: ['transform-runtime'],
55 | presets: ['es2015', 'stage-0', 'react'],
56 | }
57 | }
58 | ]
59 | },
60 | plugins: [
61 | new webpack.HotModuleReplacementPlugin(), // Hot reloading
62 | new webpack.NoEmitOnErrorsPlugin(), // Webpack will let you know if there are any errors
63 |
64 | // Declare global variables
65 | new webpack.ProvidePlugin({
66 | React: 'react',
67 | ReactDOM: 'react-dom',
68 | _: 'lodash'
69 | }),
70 |
71 | new HtmlWebpackPlugin({
72 | filename: 'index.html',
73 | template: './src/index.html',
74 | hash: false
75 | })
76 | ]
77 | }
--------------------------------------------------------------------------------