WordPress is one of the most popular CMS in the world, it is estimated that about 27.5% of the web sites are based on this system. So when creating mobile applications, there is a great chance that we will need to know how to work with WordPress based sites.
Before we start writing anything on android, let’s log into WordPress and install the “WP REST API” plug-in. This plug-in extends WordPress’s ability so we will be able to easily access resources through the appropriate URI and HTTP protocol.
If everything was installed correctly at: https://binaryalchemist.pl/wp-json/wp/v2/posts we should get in Json most recently posted posts on the site. Same way address https://binaryalchemist.pl/wp-json/wp/v2/comments will return last published comments.
When we have sorted it out we can prepare our application which will work with wordpress:
public class MainActivity extends AppCompatActivity {
ListView listView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView) findViewById(R.id.listView);
new getJSONAsyncTask().execute();
}
private class getJSONAsyncTask extends AsyncTask<String, Void, String> {
@Override
protected void onPreExecute() {
}
@Override
protected void onPostExecute(String result) {
try {
JSONArray jsonArray = new JSONArray(result);
ArrayList<String> titleList = new ArrayList<String>();
for (int num = 0; num < jsonArray.length(); num++) {
JSONObject postObject = (JSONObject) jsonArray.get(num);
JSONObject titleObject = (JSONObject) postObject.get("title");
titleList.add(titleObject.getString("rendered"));
}
ArrayAdapter adapter = new ArrayAdapter(getApplicationContext(),
android.R.layout.simple_list_item_1, titleList);
listView.setAdapter(adapter);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected String doInBackground(String... params) {
String result = getJsonFromHttp("https://binaryalchemist.pl/wp-json/wp/v2/posts?per_page=50");
return result;
}
}
public String getJsonFromHttp(String jsonUrl) {
URL url;
String responseData = null;
try {
url = new URL(jsonUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(10000);
conn.setConnectTimeout(15000);
conn.setRequestMethod("GET");
conn.setAllowUserInteraction(false);
conn.connect();
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;
while ((line = bufferedReader.readLine()) != null) {
stringBuilder.append(line + "\n");
}
bufferedReader.close();
responseData = stringBuilder.toString();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return responseData;
}
}
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:app="https://schemas.android.com/apk/res-auto"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="binaryalchemist.wordpressconnector.MainActivity"
android:background="#428bca">
<ListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
</ListView>
</android.support.constraint.ConstraintLayout>
Once we have the plugin installed we only need to connect to the interesting site and download its resources in the form of json, we are using an asynchronous task to not block the device. In my case, I decided to download the titles of all the blog posts I created and display them as a listview. The result is as follows (in Polish):
This way we can quickly get interesting information from the server running WordPress. Problems can start when we need access to resources requiring authorization.
oAuth 2.0
Many times we will have a situation in which we do not want every user to have access to all the information provided by our server. By default, the plug-in “wp rest api” restricts access to previous versions of the article for non-authorized users. Connecting to https://binaryalchemist.pl/wp-json/wp/v2/posts/{id}/revisions will return us 401 status, ie no permissions.
There are several types of authorization the simplest one is to send login and password with url, but recommended and more secure method is authorization using the oAuth protocol, so we will use it here. The protocol we use is oAuth 2.0
Thanks to oAuth we can work with our WordPress site without having to save in device confidential information like login or password. At first it would be good to understand how the oAuth authorization works, the following sequence diagram might help:
At first, we register our application on the server, obtaining a unique identification number, app secret, and defining a callback page where we will download the code needed to create an access token. When we want to access resources we send a request to the server for our authorization. We log into wordpress. If we succeed, we will be redirected to a predefined callback page where we will get the code to generate a token request. We are sending another request to generate our access token containing our unique identifier, request token, and the grant_type parameter. If everything goes well we will be able to access the selected resources using the newly created access token. This token can be used until its validity expires.
The whole thing may seem quite complicated, but overall work is largely about sending a request to our server to get a request token. The request is as follows:
https://binaryalchemist.pl/?oauth=authorize&client_id=our_client_id&response_type=code
where:
https://binaryalchemist.pl/?oauth=authorize – default address (endpoint) responsible for generating request token
client_id – The application id number available in the wordpress panel
response_type – The name of the variable under which the request token will be generated (in this case the name is code)
If all goes well we’ll get the url with a unique identifier in the code parameter
We send another request this time using POST method to create an access token
https://binaryalchemist.pl/?oauth=token&grant_type=authorization_code&client_id=our_client_id&
client_secret=our_client_secret&code=l7mgwqpet8evt59ovvpj6igftvoxpuqq1pnyvztm
where:
https://binaryalchemist.pl/?oauth=token – default address (endpoint) responsible for generating access tokena
grant_type – type of credentials sending to server
client_id – The application id number available in the wordpress panel
client_secret – app secret identifying app available in the wordpress panel
code – unique code generated in the previous step
If everything goes smoothly, we should create an access token which can be used to authenticate and download our resources.
Let’s keep in mind that request token is valid only for 30 seconds.
Let’s move on to our wordpress server. Firstly install the “WP OAuth Server” plugin. It is responsible for managing the authentication and tokens on our server. In it we create a new client. We give the name of client and address of the page where we will be redirected after successful login.
After creating client we will have access to app id and app secret remember this data they will be used in next steps.
Time to write our android aplication. In our work, we will use scribe library which is used as oAuth client. This libary will greatly simplifie the implementation of oAuth protocol, and also works with a large number of external api. Unfortunately, by default it does not work with wordpres but we can handle it. So let’s add this library to gradle:
compile 'org.scribe:scribe:1.3.7'
Let’s create a new Provider class that will expand DefaultApi20 and implement two methods getAccessTokenEndpoint() which specifies the address where we can obtain the access token and getAuthorizationUrl() address with parameters where we will retrieve the request token:
public class Provider extends DefaultApi20 {
@Override
public String getAccessTokenEndpoint() {
return "https://binaryalchemist.pl?oauth=token";
}
@Override
public String getAuthorizationUrl(OAuthConfig config) {
StringBuilder authUrl = new StringBuilder();
authUrl.append("https://binaryalchemist.pl?oauth=authorize");
authUrl.append("&client_id=").append(OAuthEncoder.encode(config.getApiKey()));
authUrl.append("&response_type=").append(OAuthEncoder.encode("code"));
return authUrl.toString();
}
}
We will try to create a new post on the site, which is only posible by authorized users. So in the main activity we write the following code:
public class MainActivity extends AppCompatActivity {
Verifier verifier;
OAuthService service;
Token accessToken;
final String consumerKey = "TfAr8xOF02Nupmes0g28CMHMV0B5SD"; //api key
final String consumerSecret = "jMTTd1r2Hr5vWuRaWSrZ04MIQIIsOB"; //api secret
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
service = new ServiceBuilder()
.provider(Provider.class)
.apiKey(consumerKey)
.apiSecret(consumerSecret)
.build();
final String authorizationUrl = service.getAuthorizationUrl(EMPTY_TOKEN);
WebView webView;
webView = (WebView) findViewById(R.id.webView1);
webView.getSettings().setJavaScriptEnabled(true);
webView.setWebViewClient(new WebViewClient() {
@Override
public void onPageFinished(WebView view, String url) { //listen for page change and check if its callback page
String currentUrl = view.getUrl();
if (currentUrl.contains("https://binaryalchemist.pl/callback?")) {
String code = currentUrl.replace("https://binaryalchemist.pl/callback?code=", "");
verifier = new Verifier(code);
// new oAuthAsyncTask(getApplicationContext()).execute(); //we will implement it in next step
}
}
});
webView.loadUrl(authorizationUrl);
}
}
When using the scribe library, we create a service object responsible for cooperation with oAuth. We open the WebView and log in to our wordpress. If everything goes according to our plan, we will sucessfuly log in and will be redirected to callback page. There we will get the generated code from url, we have a request token. Now we need to get the access token, let’s continue:
private class oAuthAsyncTask extends AsyncTask<String, Void, String> {
private Context con;
public oAuthAsyncTask(Context c) {
this.con = c;
}
@Override
protected void onPreExecute() {
}
@Override
protected void onPostExecute(String result) {
System.out.print(result);
}
@Override
protected String doInBackground(String... params) {
oAuth();
return null;
}
}
public void oAuth() {
String requestUrl = "https://binaryalchemist.pl/wp-json/wp/v2/posts/";
OAuthRequest request = new OAuthRequest(Verb.POST, "https://binaryalchemist.pl?oauth=token"); //add url paameters
request.addBodyParameter(OAuthConstants.CLIENT_ID, consumerKey);
request.addBodyParameter(OAuthConstants.CLIENT_SECRET, consumerSecret);
request.addBodyParameter(OAuthConstants.CODE, verifier.getValue());
request.addBodyParameter("grant_type", "authorization_code");
Response response = request.send();
try {
JSONObject tokenObject = new JSONObject(response.getBody()); //read and create token
String token = tokenObject.getString("access_token");
accessToken = new Token(token, "", response.toString());
} catch (JSONException e) {
e.printStackTrace();
}
String jsonObject ="{\"title\":\"My New Title\",\"status\":\"publish\"}"; //create new post in jason
System.out.println(jsonObject);
OAuthRequest secretRequest = new OAuthRequest(Verb.POST, requestUrl);
secretRequest.addHeader("Content-Type", "application/json");
secretRequest.addPayload(jsonObject);
service.signRequest(accessToken, secretRequest); /sign request with access token
Response secretResponse = secretRequest.send();
Log.d("OAuthTask", secretResponse.getBody());
}
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:app="https://schemas.android.com/apk/res-auto"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="binaryalchemist.wordpressconnector.MainActivity"
android:background="#428bca">
<WebView
android:id="@+id/webView1"
android:layout_width="match_parent"
android:layout_height="match_parent"></WebView>
</android.support.constraint.ConstraintLayout>
We create an OAuthRequest request and provide all the necessary parameters. The request is then sent to the server we receive information about the access token in such form {“access_token”:”ri8qco0lyhdyl2256aczho3i88b9vyzoqpz0zfbb”,”expires_in”:86400, “token_type”:”Bearer”,”scope”:”basic”,”refresh_token”:”ikplek9bt3to4t5nblqsvdf2wojk9pm7m4plfinn”}. Based on this data, we create an access token.
Finally, we create a new request OAuthRequest secretRequest, add to this request json data representing new post (all parameters of post and other objects can be found in the rest api documentation httpss://developer.wordpress.org/rest-api/reference/) and sign with the generated token.
If everything goes well on our site should appear new post:
By using the wp rest api we can also update and delete our data we have just to change our Verb.POST to Verb.PUT or Verb.DELETE and provide the correct url along with the post id number.
ex.
Verb.DELETE
https://binaryalchemist.pl/wp-json/wp/v2/posts/923/
will delete just created post
Wp rest api by default allows us to read, create, modify and delete objects such as Posts, Post Revisions, Categories, Tags, Pages, Comments, Taxonomies, Media, Users, Post Types, Post Statuses, Settings. However, many times we would like to have access to self-defined resources such as weather data for weather applications. Fortunately, this is possible by extending the endpoints of the plug-in. More about this can be found in its documentation at the address httpss://developer.wordpress.org/rest-api/extending-the-rest-api/adding-custom-endpoints/
Full source code for project created in Android Studio is downloadable below:
Source code