I have a Wordpress site and a web application that can be used only by the registered (Wordpress) users.
Now I'm loading wp-blog-header.php
to check if the user is logged in. Everything is working fine but because on every request (including AJAX) I have to load the Wordpress core also, it slows down my application visibly (more than 70% from the total loading time).
Is there any simple way to use the Wordpress users but without loading the entire Wordpress core?
Update: I need to know which user is logged in and also security is important.
Thank you!
I have a Wordpress site and a web application that can be used only by the registered (Wordpress) users.
Now I'm loading wp-blog-header.php
to check if the user is logged in. Everything is working fine but because on every request (including AJAX) I have to load the Wordpress core also, it slows down my application visibly (more than 70% from the total loading time).
Is there any simple way to use the Wordpress users but without loading the entire Wordpress core?
Update: I need to know which user is logged in and also security is important.
Thank you!
Share Improve this question asked Sep 12, 2011 at 19:32 VictorVictor 2632 silver badges7 bronze badges8 Answers
Reset to default 10If I had to do this, I'd use my own cookie to determine login and only load WordPress to check when necessary.
The wordpress_logged_in_{some-hash} cookie can be used to determine the user, and WordPress uses it to determine same. You can't easily reimplement that, but you can use it without loading WordPress on multiple requests.
For example, here's my cookie hash (completely made up data, but realistic):
key: wordpress_logged_in_1234567890abcdef1234567890abcdef
value: admin|1234567890|abcdef1234567890abcdef1234567890
The way WordPress knows how that cookie is valid is irrelevant, all you need to know is whether it's valid one time, then you sign it with a secret.
So, first time, the user isn't proven yet. You load wp-load.php and WP validates the cookie and logs the user in. You now do whatever you do to prove to yourself that the user has been logged in, then you set your own cookie. The key can be anything custom to you, the value you make into a message digest with a secret key using the hash_hmac function.
$key = ... // the key from the WP cookie
$value = ... // the value from the WP cookie
$hash = hash_hmac ( 'md5' , $key.$value , 'some secret key' );
You'll get back gibberish, which you send back to them using setcookie(). On future requests, they'll send this cookie back to you. You can check that first and validate it using the same hash function and secret key.
Only you can generate the hash because only you know the secret key. So if they send back a valid hash that also matches what they send for their WP cookie, then you know they've been validated with WP, through your code, before, and you can get the username right from that value (it's the first part of the cookie, obviously). Then you don't have to load WP.
The secret key, BTW, should be long and random. Not a short password. Not a dictionary word. Just large nonsensical gibberish. Line noise, and lots of it. Example key:
'GHY5hFNqq4Ntdu=3:SUp8#/+_W!- @@^@xslN*L|N+Vn;(1xo8jNyp,au$v9Ki5*'
Because I'm also using some Wordpress functions beside the users management I decided to continue to load the WP core but I made a custom file that loads only what I need and without loading the plugins. The new loading time is satisfying (it decreased from 1.5s on full WP load to 0.3s)
I've made a file called 'wp-load-minimum.php' and I call this file instead of 'wp-blog-header.php'
This is woking for WP 3.3. Here is the content of the file, If you find it useful:
<?php
//this stops wp-settings from load everything
define ('SHORTINIT',true);
error_reporting( E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_ERROR | E_WARNING | E_PARSE | E_USER_ERROR | E_USER_WARNING | E_RECOVERABLE_ERROR );
/** Define ABSPATH as this files directory */
define( 'ABSPATH', dirname(__FILE__) . '/' );
//WP config file
require ('wp-config.php');
if (SHORTINIT):
// Load the l18n library.
require( ABSPATH . WPINC . '/l10n.php' );
// Run the installer if WordPress is not installed.
wp_not_installed();
// Load most of WordPress.
require( ABSPATH . WPINC . '/class-wp-walker.php' );
//require( ABSPATH . WPINC . '/class-wp-ajax-response.php' );
require( ABSPATH . WPINC . '/formatting.php' );
require( ABSPATH . WPINC . '/capabilities.php' );
require( ABSPATH . WPINC . '/query.php' );
require( ABSPATH . WPINC . '/theme.php' );
require( ABSPATH . WPINC . '/user.php' );
require( ABSPATH . WPINC . '/meta.php' );
require( ABSPATH . WPINC . '/general-template.php' );
require( ABSPATH . WPINC . '/link-template.php' );
//require( ABSPATH . WPINC . '/author-template.php' );
require( ABSPATH . WPINC . '/post.php' );
//require( ABSPATH . WPINC . '/post-template.php' );
//require( ABSPATH . WPINC . '/category.php' );
//require( ABSPATH . WPINC . '/category-template.php' );
require( ABSPATH . WPINC . '/comment.php' );
//require( ABSPATH . WPINC . '/comment-template.php' );
require( ABSPATH . WPINC . '/rewrite.php' );
//require( ABSPATH . WPINC . '/feed.php' );
//require( ABSPATH . WPINC . '/bookmark.php' );
//require( ABSPATH . WPINC . '/bookmark-template.php' );
require( ABSPATH . WPINC . '/kses.php' );
require( ABSPATH . WPINC . '/cron.php' );
//require( ABSPATH . WPINC . '/deprecated.php' );
require( ABSPATH . WPINC . '/script-loader.php' );
require( ABSPATH . WPINC . '/taxonomy.php' );
//require( ABSPATH . WPINC . '/update.php' );
//require( ABSPATH . WPINC . '/canonical.php' );
require( ABSPATH . WPINC . '/shortcodes.php' );
require( ABSPATH . WPINC . '/media.php' );
require( ABSPATH . WPINC . '/http.php' );
require( ABSPATH . WPINC . '/class-http.php' );
require( ABSPATH . WPINC . '/widgets.php' );
require( ABSPATH . WPINC . '/nav-menu.php' );
//require( ABSPATH . WPINC . '/nav-menu-template.php' );
//require( ABSPATH . WPINC . '/admin-bar.php' );
// Load multisite-specific files.
if ( is_multisite() ) {
require( ABSPATH . WPINC . '/ms-functions.php' );
require( ABSPATH . WPINC . '/ms-default-filters.php' );
require( ABSPATH . WPINC . '/ms-deprecated.php' );
}
// Define constants that rely on the API to obtain the default value.
// Define must-use plugin directory constants, which may be overridden in the sunrise.php drop-in.
wp_plugin_directory_constants( );
// Load must-use plugins.
/*foreach ( wp_get_mu_plugins() as $mu_plugin ) {
include_once( $mu_plugin );
}
unset( $mu_plugin );*/
// Load network activated plugins.
if ( is_multisite() ) {
foreach( wp_get_active_network_plugins() as $network_plugin ) {
include_once( $network_plugin );
}
unset( $network_plugin );
}
do_action( 'muplugins_loaded' );
if ( is_multisite() )
ms_cookie_constants( );
// Define constants after multisite is loaded. Cookie-related constants may be overridden in ms_network_cookies().
wp_cookie_constants( );
// Define and enforce our SSL constants
wp_ssl_constants( );
// Create common globals.
require( ABSPATH . WPINC . '/vars.php' );
// Make taxonomies and posts available to plugins and themes.
// @plugin authors: warning: these get registered again on the init hook.
create_initial_taxonomies();
create_initial_post_types();
// Register the default theme directory root
//register_theme_directory( get_theme_root() );
// Load active plugins.
/*foreach ( wp_get_active_and_valid_plugins() as $plugin )
include_once( $plugin );
unset( $plugin );*/
// Load pluggable functions.
require( ABSPATH . WPINC . '/pluggable.php' );
//require( ABSPATH . WPINC . '/pluggable-deprecated.php' );
// Set internal encoding.
wp_set_internal_encoding();
// Run wp_cache_postload() if object cache is enabled and the function exists.
if ( WP_CACHE && function_exists( 'wp_cache_postload' ) )
wp_cache_postload();
do_action( 'plugins_loaded' );
// Define constants which affect functionality if not already defined.
wp_functionality_constants( );
// Add magic quotes and set up $_REQUEST ( $_GET + $_POST )
wp_magic_quotes();
do_action( 'sanitize_comment_cookies' );
/**
* WordPress Query object
* @global object $wp_the_query
* @since 2.0.0
*/
$wp_the_query = new WP_Query();
/**
* Holds the reference to @see $wp_the_query
* Use this global for WordPress queries
* @global object $wp_query
* @since 1.5.0
*/
$wp_query =& $wp_the_query;
/**
* Holds the WordPress Rewrite object for creating pretty URLs
* @global object $wp_rewrite
* @since 1.5.0
*/
$wp_rewrite = new WP_Rewrite();
/**
* WordPress Object
* @global object $wp
* @since 2.0.0
*/
$wp = new WP();
/**
* WordPress Widget Factory Object
* @global object $wp_widget_factory
* @since 2.8.0
*/
$GLOBALS['wp_widget_factory'] = new WP_Widget_Factory();
do_action( 'setup_theme' );
// Define the template related constants.
wp_templating_constants( );
// Load the default text localization domain.
load_default_textdomain();
// Find the blog locale.
$locale = get_locale();
$locale_file = WP_LANG_DIR . "/$locale.php";
if ( ( 0 === validate_file( $locale ) ) && is_readable( $locale_file ) )
require( $locale_file );
unset($locale_file);
// Pull in locale data after loading text domain.
require( ABSPATH . WPINC . '/locale.php' );
/**
* WordPress Locale object for loading locale domain date and various strings.
* @global object $wp_locale
* @since 2.1.0
*/
$GLOBALS['wp_locale'] = new WP_Locale();
// Load the functions for the active theme, for both parent and child theme if applicable.
/*if ( ! defined( 'WP_INSTALLING' ) || 'wp-activate.php' === $pagenow ) {
if ( TEMPLATEPATH !== STYLESHEETPATH && file_exists( STYLESHEETPATH . '/functions.php' ) )
include( STYLESHEETPATH . '/functions.php' );
if ( file_exists( TEMPLATEPATH . '/functions.php' ) )
include( TEMPLATEPATH . '/functions.php' );
}*/
do_action( 'after_setup_theme' );
// Load any template functions the theme supports.
//require_if_theme_supports( 'post-thumbnails', ABSPATH . WPINC . '/post-thumbnail-template.php' );
// Set up current user.
$wp->init();
/**
* Most of WP is loaded at this stage, and the user is authenticated. WP continues
* to load on the init hook that follows (e.g. widgets), and many plugins instantiate
* themselves on it for all sorts of reasons (e.g. they need a user, a taxonomy, etc.).
*
* If you wish to plug an action once WP is loaded, use the wp_loaded hook below.
*/
do_action( 'init' );
// Check site status
if ( is_multisite() ) {
if ( true !== ( $file = ms_site_check() ) ) {
require( $file );
die();
}
unset($file);
}
/**
* This hook is fired once WP, all plugins, and the theme are fully loaded and instantiated.
*
* AJAX requests should use wp-admin/admin-ajax.php. admin-ajax.php can handle requests for
* users not logged in.
*
* @link http://codex.wordpress/AJAX_in_Plugins
*
* @since 3.0.0
*/
do_action('wp_loaded');
endif;
//require( ABSPATH . WPINC . '/pluggable.php' );
For Wordpress 4.9: As I cant comment (new user). The final soultion (single WP install) I use for making is_user_logged_in()
and current_user_can()
work, is as follow below. We require('wp-load.php')
first (to skip wp() in load-blog-header.php), and get ABSPATH
constant then, manually includes exactly all the stuff needed.
Using define('SHORTINIT', true)
+ require('wp-load.php')
+ manually includes:
Pageload: 1.05 sek - included files: 43 files
Comparing: Using ONLY require('wp-load.php')
:
Pageload: 1.35 sek - included files: 419 files
The time difference (0.3 sek) might differ from installs and PHP engines, but while validating many requests on one pageload -things adds up!
Remember to use relative call to WP installed dir. From a Wordpress custom plugin dir, inside one subdir level, normal install, a path should be like:
$wordpress = '../../../../wp-load.php';
Then:
define('SHORTINIT', true);
include_once $wordpress;
require_once ( ABSPATH . WPINC . '/class-wp-user.php' );
require_once ( ABSPATH . WPINC . '/class-wp-roles.php' );
require_once ( ABSPATH . WPINC . '/class-wp-role.php' );
require_once ( ABSPATH . WPINC . '/class-wp-session-tokens.php' );
require_once ( ABSPATH . WPINC . '/class-wp-user-meta-session-tokens.php' );
require_once ( ABSPATH . WPINC . '/formatting.php' );
require_once ( ABSPATH . WPINC . '/capabilities.php' );
//require_once ( ABSPATH . WPINC . '/query.php' ); // - might be useful
require_once ( ABSPATH . WPINC . '/user.php' );
require_once ( ABSPATH . WPINC . '/meta.php' );
wp_cookie_constants();
require_once ( ABSPATH . WPINC . '/vars.php' );
require_once ( ABSPATH . WPINC . '/kses.php' );
require_once ( ABSPATH . WPINC . '/rest-api.php' );
require_once ( ABSPATH . WPINC . '/pluggable.php' );
After this, user validation is accessable. For other task, running on one or two requests, tracking down other needed files might not be not worth 0.3 sek. Skip the SHORTINIT
constant and manually clutter.
Wordpress itself only is on or off. Sometimes, but that's only by chance and not by design, you can work around that. But in your case, I'm not really sure if it's possible.
Instead of wp-blog-header.php
you can try to only load the WP functions, include wp-load.php
instead. Maybe that helps.
You could try to access the table directly. If you know the salt of the password files you could have them log in via your own system, salt the password yourself (look at how wordpress does it) and keep track of them yourself. If you want the ability to traverse between your own system and wordpress without re-authentication, you could make a plugin to wordpress that passes the current users session to your system.
The fastest you can get with WP is making custom wrapper that will define SHORTINIT
and then load core. This will make core load stop right after database is connected and before most of APIs and extensions (theme and plugins) are processed.
From there you can try to get by database alone or selectively load parts of core you need.
This is quite a messy approach, but it is as close to lighter core load as things get in WP.
Seems there was already discussion about that. So, check updates at: https://core.trac.wordpress/ticket/37584
If you just want to allow all Wordpress users to use the web app, you can use the Wordpress user management system and just check whether the user is logged in or not.
To check this you will need to check whether the cookie named wordpress_logged_in_{some-hash}
is present. If not, redirect the user to the Wordpress login page. The {some-hash}
part of the cookie name is just a series of letters and digits.