In this blog post, we’ll walk you through how to build a secure login and post creation system in WordPress using a custom plugin. This system is designed specifically for React Native mobile apps, but it can also be used with any client that can interact with a REST API.
🏘️ Plugin Setup
1. Create Plugin Directory and File
Create the following folder inside your wp-content/plugins/ directory:
wp-mobile-login/
└── wp-mobile-login.php
2. Plugin Header and Login Endpoint
Paste the following code into wp-mobile-login.php:
<?php
/*
Plugin Name: WP Mobile Login API
Description: Provides a REST API endpoint for mobile app login using email and password.
Version: 0.1
Author: Chethan S Poojary
*/
if (!defined('ABSPATH')) {
exit; // Prevent direct access
}
add_action('rest_api_init', function () {
register_rest_route('mobile/v1', '/login', [
'methods' => 'POST',
'callback' => 'wp_mobile_login_handler',
'permission_callback' => '__return_true',
]);
});
function wp_mobile_login_handler(WP_REST_Request $request) {
$email = sanitize_text_field($request->get_param('email'));
$password = $request->get_param('password');
$response = [
'data' => [],
'msg' => 'Invalid email or password',
'status' => false,
];
if (!$email || !$password) {
$response['msg'] = 'Email and password are required';
return new WP_REST_Response($response, 400);
}
$user = get_user_by('email', $email);
if ($user && wp_check_password($password, $user->user_pass, $user->ID)) {
$token = bin2hex(random_bytes(16));
update_user_meta($user->ID, 'auth_token', $token);
$response['status'] = true;
$response['msg'] = 'Successfully Authenticated';
$response['data'] = [
'auth_token' => $token,
'user_id' => $user->ID,
'user_login' => $user->user_login,
];
return new WP_REST_Response($response, 200);
}
return new WP_REST_Response($response, 403);
}
🚀 How to Use From React Native or Postman
Login:
POST https://yourdomain.com/wp-json/mobile/v1/login
Body (JSON):
{
"email": "user@example.com",
"password": "securepassword"
}
React Native Approch:
import React, { useState } from 'react';
import {
View,
Text,
TextInput,
TouchableOpacity,
ActivityIndicator,
StyleSheet,
Alert
} from 'react-native';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { router } from 'expo-router';
interface LoginResponseData {
auth_token: string;
user_id: string | number;
user_login: string;
}
export default function Profile() {
const [email, setEmail] = useState<string>('');
const [password, setPassword] = useState<string>('');
const [validating, setValidating] = useState<boolean>(false);
const validate = async () => {
setValidating(true);
const formData = new FormData();
formData.append('type', 'login');
formData.append('email', email);
formData.append('password', password);
try {
const response = await fetch('http://blogchethanspoojarycom.local/wp-json/mobile/v1/login', {
method: 'POST',
body: formData,
});
const responseJson = await response.json();
if (responseJson.status) {
await saveToStorage(responseJson.data);
setValidating(false);
console.log('Login sucessfull:', responseJson)
router.replace('/(tabs)'); // Adjust this route to your needs
} else {
setValidating(false);
Alert.alert(
'Login Failed',
responseJson.msg || 'Incorrect email or password'
);
}
} catch (error) {
setValidating(false);
Alert.alert('Error', 'An error occurred. Please try again.');
console.error(error);
}
};
const saveToStorage = async (userData: LoginResponseData) => {
if (userData) {
await AsyncStorage.setItem(
'user',
JSON.stringify({
isLoggedIn: true,
authToken: userData.auth_token,
id: userData.user_id,
name: userData.user_login,
})
);
return true;
}
return false;
};
return (
<View style={styles.container}>
<Text style={styles.title}>WordPress Login</Text>
<TextInput
value={email}
onChangeText={setEmail}
placeholder="Email"
autoCapitalize="none"
style={styles.input}
keyboardType="email-address"
/>
<TextInput
value={password}
onChangeText={setPassword}
placeholder="Password"
autoCapitalize="none"
secureTextEntry
style={styles.input}
/>
<TouchableOpacity style={styles.button} onPress={validate} disabled={validating}>
{validating ? (
<ActivityIndicator color="#fff" />
) : (
<Text style={styles.buttonText}>Login</Text>
)}
</TouchableOpacity>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 24,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#fff',
},
title: {
fontSize: 22,
marginBottom: 24,
fontWeight: 'bold',
},
input: {
width: '100%',
borderWidth: 1,
borderColor: '#dcdcdc',
borderRadius: 4,
padding: 12,
fontSize: 16,
marginBottom: 16,
},
button: {
backgroundColor: '#007aff',
padding: 14,
borderRadius: 4,
minWidth: '100%',
alignItems: 'center',
},
buttonText: {
color: '#fff',
fontWeight: 'bold',
},
});