Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

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

migrated from stackoverflow.com Sep 12 '11 at 21:54

This question came from our site for professional and enthusiast programmers.

6 Answers 6

up vote 5 down vote accepted

If 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*'

share|improve this answer
    
Thank you, this is what I was looking for! –  Victor Sep 13 '11 at 9:35

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.org/AJAX_in_Plugins
 *
 * @since 3.0.0
 */
do_action('wp_loaded');

endif;

//require( ABSPATH . WPINC . '/pluggable.php' );
share|improve this answer
    
This is a good idea. One suggestion: You can probably ditch plugin loading and query set up (depending on your use case, of course). –  chrisguitarguy Mar 9 '12 at 14:33

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.

share|improve this answer
    
wp-blog-header.php basically loads wp-load.php so there is no diffrence... –  Victor Sep 12 '11 at 20:11
1  
@Victor: There is a difference. It spares the fire-up of wp(); which is actually pretty expensive. –  hakre Sep 12 '11 at 20:14
    
OK, now I'm trying to figure out what exactly wp() does. –  Victor Sep 12 '11 at 20:21
    
I've made some test with wp-load.php instead of wp-blog-header.php, everything seems to work fine but the loading time is the same. –  Victor Sep 12 '11 at 20:36
    
@Victor: Are you using your watch while pressing F5 or how do you actually measure? :) Anyway, don't use WordPress if you actually need a framework. You can try to only load the functions you actually require instead. But you need to look for them bit by bit. Just include the files you actually need, like for user functions and the database access probably. –  hakre Sep 12 '11 at 20:50

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.

share|improve this answer

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.

share|improve this answer
    
I need to know which user is logged in and also security is important. –  Victor Sep 12 '11 at 19:50

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.

share|improve this answer
    
SHORTINIT is a good approach, but this means that all the functions for checking users and the hashes and such won't get loaded. You could reimplement that, but messy, as you said. –  Otto Sep 12 '11 at 23:22
    
@Otto Probably not reimplement, but rather load those parts of core by hand. And if there are any modifications to users are being done by plugins load those by hand as well. Yeah, this is quite involved approach. But next alternative for better performance is ditching WP entirely and working with database directly, which is even more messy. –  Rarst Sep 13 '11 at 8:45

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.