How to Integrate WordPress Authentication in External PHP Applications
Posted onWith WordPress crossing over from simple blogging software to a fully scalable CMS, it’s no wonder why so many webmasters have turned over to this popular platform to manage more complex sites. Lots of them are not only maintaining their online community with WordPress, but they’re also managing their whole customer base. Just think of the WooCommerce plugin that can turn your WordPress site into a fully-featured eCommerce store for instance.
In older versions of WordPress, it was easy to perform PHP authentication against the “wp_users” table since it simply used the md5 hashing function to encrypt passwords. But now, WordPress is using its own hashing function, making things a little bit more complicated.
In this tutorial, you will learn how to integrate the WordPress authentication functions in an external PHP application.
PHP Files Location
Since WordPress uses domain-based cookies to keep users logged in, it is important that your PHP files are hosted on the same domain. Using a different domain or subdomain will cause the authentication to fail.
For this tutorial, we’ll assume that WordPress is installed in the website’s root folder (https://www.mywebsite.com/) and that your PHP files are hosted in a subfolder (https://www.mywebsite.com/control-panel/).
We will need to create three (3) files to make this work:
- /control-panel/wp-authenticate.php
- /control-panel/index.php
- /control-panel/login.php
Let’s see how all these files work together. I have inserted a lot of comments throughout the PHP code so it’s pretty self-explanatory.
wp-authenticate.php
This file will contain all the common PHP functions and settings used by the other PHP files. Copy the following content into wp-authenticate.php:
<?php /*** UNCOMMENT THIS LINE TO DISPLAY ALL PHP ERRORS ***/ // error_reporting(E_ALL); init(); function authenticate() { $username = htmlspecialchars($_POST["username"]); $password = htmlspecialchars($_POST["password"]); $user = get_user_by('login', $username); /*** COMPARE FORM PASSWORD WITH WORDPRESS PASSWORD ***/ if(!wp_check_password($password, $user->data->user_pass, $user->ID)): return false; endif; wp_set_current_user($user->ID, $username); /*** SET PERMANENT COOKIE IF NEEDED ***/ if($_POST["remember"] == "1") wp_set_auth_cookie($user->ID, true); else wp_set_auth_cookie($user->ID); /*** REDIRECT USER TO PREVIOUS PAGE ***/ if(isset($_SESSION["return_to"])): $url = $_SESSION["return_to"]; unset($_SESSION["return_to"]); header("location: $url"); else: header("location: /control-panel/"); endif; } function login() { if(!is_user_logged_in()): /*** REMEMBER THE PAGE TO RETURN TO ONCE LOGGED IN ***/ $_SESSION["return_to"] = $_SERVER['REQUEST_URI']; /*** REDIRECT TO LOGIN PAGE ***/ header("location: /control-panel/login.php"); endif; } function init() { /*** INITIATING PHP SESSION ***/ if(!session_id()) session_start(); /*** LOADING WORDPRESS LIBRARIES ***/ define('WP_USE_THEMES', false); require_once("../wp-load.php"); } ?>
index.php
This is the page we want to protect from public visitors. The call to “login()” makes sure the visitor has been authenticated before displaying the page content. If the visitor is already logged in, it will display his/her full name.
<?php /*** PREVENT THE PAGE FROM BEING CACHED BY THE WEB BROWSER ***/ header("Cache-Control: no-cache, must-revalidate"); header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); require_once("wp-authenticate.php"); /*** REQUIRE USER AUTHENTICATION ***/ login(); /*** RETRIEVE LOGGED IN USER INFORMATION ***/ $user = wp_get_current_user(); ?> <!DOCTYPE html> <html lang="en"> <head> <title>Login</title> </head> <body> <p>Welcome <?php echo $user->user_firstname . " " . $user->user_lastname; ?></p> <p><a href="/control-panel/login.php?logout=true">Click here to log out</a></p> </body> </html>
login.php
The login page will perform both login and logout operations. As you can see, the login page will send the form data to itself so it can display an error message if the authentication fails. If the authentication is successful, the call to “authenticate()” will redirect the visitor to the previous (protected) page.
<?php /*** PREVENT THE PAGE FROM BEING CACHED BY THE WEB BROWSER ***/ header("Cache-Control: no-cache, must-revalidate"); header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); require_once("wp-authenticate.php"); /*** LOG OUT CURRENT USER ***/ if($_GET['logout'] == 'true') wp_logout(); /*** IF THE FORM HAS BEEN SUBMITTED, ATTEMPT AUTHENTICATION ***/ if(count($_POST) > 0) authenticate(); ?> <!DOCTYPE html> <html lang="en"> <head> <title>Control Panel</title> </head> <body> <form action="login.php" method="post"> <?php if(count($_POST) > 0) echo "<p>Invalid user name or password.</p>"; ?> <input type="text" autocomplete="off" placeholder="Username" name="username"/> <input type="password" autocomplete="off" placeholder="Password" name="password"/> <label><input type="checkbox" name="remember" value="1" />Remember me</label> <button type="submit" value="Submit">Submit</button> </form> </body> </html>
Conclusion
While the inclusion of “wp-load.php” will make some WordPress functions available to your PHP application, it is important to note that they may not all work correctly so it is not recommended to rely on them too much. However, some functions do work correctly and they might come in handy.
For instance:
- is_super_admin(): This function will check if the current user is a WordPress administrator.
- get_avatar(): Get the user’s avatar.
- current_user_can(): If you’ve assigned different roles to your WordPress users, you can use this function to restrict access to some private pages content. Read this page to learn how to add new roles.
If you encounter any problem with the authentication process, try using the Live HTTP Headers add-on for Firefox to see what data is exchanged between the browser and the web server.
Tinkering with the core WordPress code is *extremely* ill-advised. You should probably re-write your page so as to implement this as a plugin — but if you advise people to edit the actual core WordPress code you are doing them an *extreme* dis-service.
Hi Sophia,
I think you did not understand this tutorial correctly. It does not imply to modify the core WordPress code at all. The three files mentioned are NEW files you need to create to make this work.
These 3 new files need to be incorporated in your PHP project.
Basically, this tutorial is about integrating the WordPress authentication functions into a PHP project. This has absolutely no effect on your WordPress installation.
This sounds promising!!
I want to create a second backend to a WordPress Site made on Laravel or Yii2. Your solution seems useful for this purpose. I just wonder if those authentication functions will remain the same way or will change depending on WP version.
A big thanks! Save lot of time! ;)
OK, this is absolutely awesome – clean and elegant. I have been banging my head against the wall for about 8 hours now on this maybe you can point me in the right direction. In the same directory I have two php files. The simple test one works fine and correctly detects the loggedIn/LoggedOut state. When I incorporate your code into mine though, it always says that it is loggedOut even when the user is logged in. What might I have done in the code that would be interfering with is_user_logged_in() and $user = wp_get_current_user?
great tutorial. I have a couple of issues:
1. toe login you must enter your username/password twice for some reason.
2. displaying roles seems to be a little unreliable. they don’t show up immediately.
have you seen these before?
thanks
Hi Stéphane:
I need authenticate users from another data base with a security token, is it possible with this solution?
Thks!
No, WordPress will connect to its own database automatically by default.
There are another way to connect this users? and set permissions to these?
I was wondering if this can output a ‘LoggedUserID’? I want to try this but I’m not quite sure if it’s the right fit for what I’m currently doing. Basically, what I needed to get is the userid so it can be used on the external PHP that I’m working on but it’s proving to be a challenge since it can’t recognize or it can’t get the Session of the current user that’s logged in.
e.g.
class Users {
// This function gets called *a lot*, so it must be very quick to run. Cache stuff if necessary.
public static function LoggedUserID() {
return isset($_SESSION[‘userID’]) ? $_SESSION[‘userID’] : null;
}
This is fantastic –thanks! I have it working with WordPress 4.8.2. I added some code to make sure only admin roles will be logging and do some additional redirection with that.
This really helped. I did not even know you could use WordPress to authenticate users for your own little sub-app in the same directory as your WordPress site. Stoked on this bro!!
Thanks, Stéphane! Great post just what I was looking for!
Thanks – exactly what I’m looking for to kickstart a nice add-on app development to make an additional database table fully searchable (via jQuery QueryBuilder) for the Admins and Moderators. The additional database I create is there to support some features I’ve build into the network via plugins and basically consists of >125K records with product information (not WooCommerce products).
I just quickly tested it with my MultiSite installation of WordPress 4.9.9 and it seems to works great with both the “Members” (by Justin Tadlock) and the “Password bcrypt” (by Roots) plugins enabled network wide. When I run into issues I’ll let you know but for now a big thanks for not having to create this from scratch :)
Oh yeah – one little remark, I reckon it would make sense to supply the password field with a type=”password” instead of type=”text” ;)
Thanks for letting me know. I’ve made the correction.
Hey, thanks for that tutorial. I just asked why it isnt possible to have installed wordpress in a subdirectory of my root folder.
My website is installed in root->website and my wordpress is installed in root->website->wordpress
This wont work, but if i switch this directions as you mentioned in your tutorial it will work. Does somebody know how to get it working?
As long as everything is hosted on the same domain or subdomain, you’re fine.
Hi Stephane! Great tutorial. Totally helped me with a basic inhouse app. However, for some reason, when i refresh the index.php, it always goes to login.php. Any way for the user to stay logged-in or for not to go back to login.php?
Thank you, this is just what I was looking for.
But be careful with the use of htmlspecialchars on wp_authenticate.php:
$username = htmlspecialchars($_POST[“username”]);
$password = htmlspecialchars($_POST[“password”]);
If username or password contain special characters, something which should be encouraged in order to have strong passwords, they are escaped and authentication always fails.