Linking WordPress and React Native

Introduction

In this tutorial we are going to be building a simple mobile app using React Native called ‘Music News’ which will pull posts from a WordPress website via the WP REST API and display them to the user every time they tap to read more about the news. We’ll start with this and you can dig more and do more by reading and understanding the documentation.

As mobile developers, integrating a data source is a very important aspect of building mobile apps. Having an organized data source ready for integration would make development easy and also reduce the time taken to build and develop mobile apps.

WordPress as a backend can be very effective if you're building mobile applications that have a lot of consumable content such as a mobile application for a blog, e-commerce website, and so on.

It can provide standard endpoints to return the data you need and also provides standard documentation for all the endpoints you'll require.

Prerequisites

To follow through with this lesson, a basic understanding of the following are required:

  • WordPress
  • React Native

You also need to have the following installed:

  • PHP 5.6+
  • Node 8.3+
  • React Native CLI

Getting started

What is WordPress?

WordPress is the easiest and fastest way to build your website. It's free and open source and it's based off two very popular technologies, PHP and MySQL.

It is stated that over 29% of websites on the internet are WordPress powered websites.

WordPress is also a content management tool. It allows you to manage content posted on your website easily without the need for you to know anything technical and that's great because you don't have to be a programmer to be able to create and manage your website by yourself. There's a wide variety of websites you can build using WordPress and some of them includes:

  • Blogs
  • Resumes
  • Creative portfolios
  • Forums
  • Brand or business websites
  • E-commerce or shopping websites

WordPress can be an excellent tool to create your website because:

  • It's free and open source: that means you'll never need to pay for WordPress and if you're technical, you can also go ahead to add your own feature and functionality to it.
  • It is easy to install: you can easily install WordPress and get started as the installation process is fast, easy to understand and not technical so therefore can be done by anyone.
  • It's extensible: WordPress can be extended and customized by using themes to change how your website looks. There is a large plugin ecosystem to add custom functionality.
  • Support: finding help when you run into issues while setting up or managing your WordPress site is very easy. There's the official support and also so many other WordPress blogs, companies, and communities that provide free and premium support for websites using WordPress.

What is React Native?

React Native is a mobile JavaScript framework for building real native mobile applications for iOS and Android. It’s based on React made by Facebook's engineering team which is a JavaScript library for building user interfaces.

Unlike a hybrid application that allows you to write your code in HTML and CSS and then renders it in a native web view container or component, React Native calls Objective-C and Java APIs respectively to render your JSX (a combination of JavaScript and XML-esque markup which is the standard way React applications are written) codes into user interface components on your device.

Some of the known pros of React Native:

  • Cross Platform: React Native allows you to use the same codebase to compile and build for multiple platforms like Android and iOS. This also eventually saves development cost.
  • Performance: applications built using React Native have good performance on the device since they are rendered natively.
  • Community: the React and React Native community is solid despite it still being considered an emerging technology. There's a lot of communities and blogs that provide support for React Native issues.
  • Fast Development: because of its ability to build cross-platform, it saves time while developing application since you don't need to rewrite any special code for another platform and code re-usability is supported.

Some of the known cons of React Native:

  • It's new: it's still considered as a new technology and therefore not stable as it comes with the caveats of using an unstable technology
  • Future Plans: React Native was built by the engineering team at Facebook and has since led to the concern of copyright and privacy issues and also its future because the project can be discontinued by the team.

What is an API?

API stands for Application Programming Interface. It can be seen as a component that allows for interaction between two programming languages, software libraries, software tools, and so on. It also specifies a set of rules that should be followed in order to interact and communicate with underlying data.

An API could mean something else, depending on the context used and in this context, an API refers to a software component we will interact with to provide us with relevant raw data to be used inside our application.

Configuring WordPress to have an API

To get started, the first step would be to install the WordPress REST API plugin to our already existing WordPress installation. My WordPress site is on my local device so I'll be installing it there.

  • Go to Plugins > Add New > Upload Plugin.
rn-wordpress-upload-plugin
  • After uploading the plugin, make sure you activate it
rn-wordpress-install-plugin
  • Enable pretty permalinks under Settings > Permalinks because the REST API uses custom rewrite rules.
rn-wordpress-permalinks
  • Visit http://your-domain.com/wp-json/wp/v2/posts/ to make sure everything is working fine. In my own case, I have my WordPress instance installed locally on my device and in yours, visit the host you have your WordPress installed to confirm. You should see a page containing raw data of all your posts on the websites. In order to get the data in the best visual representation, you can install Postman and use it for all API calls.

We can now proceed to make more Music News posts on our WordPress normally and then visit the endpoint to see it translated into raw data that can be used in our mobile app.

rn-wordpress-data

Setting up our React Native app

To get started on this, you can follow the official docs on how to set up your React Native environment on your computer.

Once that is done, we need to initiate and create our application project.

    $ react-native init MusicNews

Once that is completed, we need to compile and build the application.

1$ react-native run-ios
2    # if using android, you can run the command below
3    $ react-native run-android

Configuring routing in our app

How our users navigate around our mobile app is important as developers, we should make navigation as easy and smooth as possible. To configure navigation in our Music News app, we'll use the react-native-router-flux library to manage navigation between the screens of our app where all the music news posts are, to the screen where we'll read each individual post. React-native-router-flux is an API on top of React Navigation and it allows you to define routes in one central place for easy management and configuration. To get started with react-native-router-flux

    $ npm install react-native-router-flux --save

Now that we have it installed, we go ahead and create our route file and configure all application routing. In the root directory of our Music News app, create a Routes.js file and the contents would look like:

1// Routes.js
2    import React, { Component } from 'react';
3    import {Platform} from 'react-native';
4    
5    // import components from react-native-router-flux
6    import {Router, Stack, Scene} from 'react-native-router-flux';
7    
8    // import our screens as components 
9    import Home from './screens/Home';
10    import ViewNews from './screens/ViewNews';
11    
12    export default class Routes extends Component<{}> {
13    
14        render() {
15            return(
16                <Router>
17                    <Stack key="root" hideNavBar={true}>
18                        <Scene key="home" component={Home} title="Home" />
19                        <Scene key="viewnews" component={ViewNews} title="View News"/>
20                    </Stack>
21                </Router>
22                )
23        }
24    }
  • Router is the main routing component.
  • A Stack is a group of Scenes with its own navigator, so you can have multiple stacks for navigating.
  • A Scene is the basic routing component for the main router and all Scene components require a key prop that must be unique.
  • A key prop is used to call the screen transition and must be unique to all screens.

Also, edit your App.js file to look like this:

1//App.js
2    import React, { Component } from 'react';
3    
4    import {
5      StyleSheet,
6      View,
7      StatusBar,
8    } from 'react-native';
9    
10    import Routes from './Routes';
11    
12    export default class App extends Component<{}> {
13    
14      render() {
15        return (
16          <View style={styles.container}>
17            <StatusBar
18              backgroundColor="#fff"
19              barStyle="dark-content"
20            />
21            <Routes/>
22          </View>
23        );
24      }
25    }
26    
27    const styles = StyleSheet.create({
28      container : {
29        flex: 1,
30      }
31    });

Designing screens for our app

React Native offers inbuilt UI components like the FlatList, Modal, Slider, Text, and so on. For the design of our home page, we will be using the Shoutem UI and react-native-render-html to render all the posts fetched from our WordPress backend.

Now that we've successfully configured routing, we need to create the screens as specified in the Routes file. We'll create a screen folder and create the files as seen below:

1$ npm install --save react-native-render-html
2    $ npm install --save @shoutem/ui
3    $ react-native link
4    $ mkdir screens && cd screens
5    $ touch Home.js ViewNews.js

Copy the code below and paste into your /screens/Home.js

1//screens/Home.js
2    import React, { Component } from 'react';
3    import {
4      StyleSheet,
5      SafeAreaView,
6    } from 'react-native';
7    
8    import {
9      Subtitle,
10      Screen,
11      Divider,
12      View, 
13      Row,
14      ListView,
15    } from '@shoutem/ui';
16    
17    import {Actions} from 'react-native-router-flux';
18    
19    export default class Home extends Component<{}> {
20    
21      home(){
22        Actions.home();
23      }
24    
25      viewNews(newspost){
26        Actions.viewnews({newspost: newspost});
27      }
28    
29      componentWillMount() {
30        this.fetchMusicNews();
31      }
32    
33      fetchMusicNews = async () => {
34        const response = await fetch("http://localhost/wordpress/wp-json/wp/v2/posts/");
35        const json = await response.json();
36        this.setState({ musicNews: json, isLoadingMusicNews: false });
37      };
38    
39      constructor(props) {
40        super(props);
41        this.renderRow = this.renderRow.bind(this);
42        this.state = {
43          isLoadingMusicNews: true,
44          musicNews: [],
45        }
46      }  
47    
48      renderRow(post) {
49        const regex = /(<([^>]+)>)/ig;
50        let newspost = {
51            postId: post.id,
52            postDate: post.date,
53            postLink: post.guid.rendered,
54            postTitle: post.title.rendered,
55            postExcerpt: post.excerpt.rendered,
56            postContent: post.content.rendered,
57            postCategory: post.categories,
58        }
59        return (
60          <Row style={{height: 80}}>
61            <View styleName="vertical stretch space-between">
62              <Subtitle 
63                numberOfLines={2} 
64                newspost={newspost} 
65                onPress={() => this.viewNews(newspost)}>
66                {post.title.rendered.replace(regex, '').toUpperCase()}
67              </Subtitle>
68            </View>
69          </Row>
70        );
71      }
72    
73      render() {
74        const regex = "/(<([^>]+)>)/ig"
75        const musicNews = this.state.musicNews;
76        return (
77          <SafeAreaView style={styles.safeArea}>
78            <Screen>
79              <View>
80                  <ListView
81                    data={musicNews}
82                    renderRow={this.renderRow}
83                  />
84              </View>
85            </Screen>
86          </SafeAreaView>
87        );
88      }
89    }
90    
91    const styles = StyleSheet.create({
92      container: {
93        flexDirection: 'column',
94        backgroundColor: '#fff'
95      },
96      safeArea: {
97        flex: 1,
98        backgroundColor: '#fff'
99      },
100    });

In the Home.js file, we import all the necessary components to build our interface. We create routing functions so we can navigate from page to page. The fetchMusicNews() is an asynchronous function that allows us to fetch data from our API configured WordPress backend and the componentWillMount() allows us to fetch the async data after the screen is rendered. The fetched data is stored in the musicNews state and will be passed to our component during rendering.

In the renderRow() we define a prop that holds data fetched from our WordPress API and we pass it to the ViewNews page so we don't have to do a network fetch to get the same data on the next screen. The data fetched is rendered as a list view using the ListView component imported from our UI library and the data is also rendered accordingly.

Our render() function renders the screen and we use the SafeAreaView component to handle the screens of newer device screen like the ones of the iPhone X and higher so the screen doesn't overlap. Our styles are also defined for different components and the applied to style individual components based on the defined rules.

Copy the code below and paste into your /screens/ViewNews.js

1// screens/ViewNews.js
2    import React, { Component } from 'react';
3    import {
4      StyleSheet,
5      SafeAreaView,
6      ScrollView,
7      Dimensions,
8    } from 'react-native';
9    
10    import {
11      Tile,
12      Title,
13      Screen,
14      Divider,
15      View, 
16      Overlay
17    } from '@shoutem/ui';
18    
19    import {Actions} from 'react-native-router-flux';
20    import HTML from 'react-native-render-html';
21    
22    export default class ViewNews extends Component<{}> {
23    
24      home(){
25        Actions.reset('home');
26        Actions.home();
27      }
28    
29      constructor(props) {
30        super(props);
31        this.state = {
32          newspost: [],  
33        }
34      }
35      render() {
36        const news = this.state.newspost;
37        const regex = /[!@#$%^&*<>0-9;]/g;
38        console.log("newspost: "+this.props.newspost);
39        return (
40          <SafeAreaView style={styles.safeArea}>
41            <Screen style={{ flex: 1 }}>
42              <ScrollView>
43              { 
44                <View>
45                  <Tile>
46                      <Overlay styleName="image-overlay">
47                        <Title style={{color: '#fff', fontWeight: '800'}} styleName="md-gutter-bottom">{this.props.newspost.postTitle.replace(regex, "").toUpperCase()}</Title>
48                        </Overlay>
49                    </Tile>
50                  <Screen style={{paddingLeft: 15, paddingRight: 15, paddingTop: 15, paddingBottom: 15, width:375}} styleName="paper">
51                    <HTML 
52                      tagsStyles={{ 
53                        body: {fontSize: 20}, 
54                        p: {fontSize: 20, fontWeight: "normal"}, 
55                        strong: {fontSize: 20,}, 
56                        blockquote: {fontSize: 20}, 
57                        a: {fontSize: 20, color: "#000"}, 
58                        em: {fontSize: 20,}, 
59                        img: {height: 250, width: 350}, 
60                      }}
61                      styleName="paper md-gutter multiline" 
62                      html={this.props.newspost.postContent} 
63                      imagesMaxWidth={Dimensions.get('window').width} 
64                      ignoredStyles={['width', 'height', 'video']}
65                      onLinkPress={(evt, href) => this.onLinkPress(href)}
66                    />
67                    <Divider styleName="line" />
68                  </Screen>
69                </View>
70              }  
71              </ScrollView>
72            </Screen>
73    
74          </SafeAreaView>
75        );
76      }
77    };
78    
79    const styles = StyleSheet.create({
80      container: {
81        flex: 1, // 1:1
82        flexDirection: 'column',
83        backgroundColor: '#fff'
84      },
85      safeArea: {
86        flex: 1,
87        backgroundColor: '#fff'
88      },
89    });

In the ViewNews.js file, we also import all the necessary components to build our interface. We create routing functions so we can navigate from page to page. The regex variable is a regular expression. We use it to remove some unwanted characters and symbols from our WordPress data.

In the render() function, we go ahead to fetch the data we stored in props from our Home.js and render it using our HTML component. The HTML component is used to render the data because the news item body sent from our WordPress API is sent with an HTML format and we can perform some extra functions like setting image size and dimensions, ignore styles, etc.

Using WordPress data

To build and compile our code:

1$ react-native run-ios
2    # If you want to build for android,you can use the command below
3    $ react-native run-android

If you are running this on your local host, chances are that you would get a network error. This is because localhost and 127.0.0.1 would refer to the internal React native app. You should replace them with the public IP of your machine or tunnel your localhost via ngrok

If you want to tunnel your WordPress app via ngrok, you can take the following steps:

  • Update ngrok (Ctrl+u when ngrok is running)
  • Adding the following two lines to wp-config: define('WP_SITEURL', 'http://' . $_SERVER['HTTP_HOST']); define('WP_HOME', 'http://' . $_SERVER['HTTP_HOST']);
  • Installing https://wordpress.org/plugins/relative-url/ in WordPress

After the build is successful, your application should look like

  • Home Screen
rn-wordpress-home-screen
  • Post Screen
rn-wordpress-post-screen

Conclusion

We can see how easy it is to use our WordPress data in our mobile application using the WP REST API Plugin. Our data can be integrated with any mobile development framework and web development framework also.

Our Music News app is simple right now, but you can go ahead to add some more styling and explore the Plugin documentation more to be able to build complex and robust applications on top of your WordPress data.

The code base to this tutorial is available in a publicly hosted GitHub repository. Feel free to experiment around with it.