Extending WP_User class and using this sub-class during the whole lifecycle

What I am trying to achieve is the following: for every user on our website, I want to do an API request to a service (local REST API interacting with another database) once and then cache the result in the WP_User (sub)class until the user will logout and login again (as this value is used on every page in the application once so otherwise it would have to be retrieved once for every page load, which is very undesirable performance-wise).

The most elegant way in terms of Separation of Concerns I have found up until now, is done by extending (subclassing) the WP_User class as per example featured in the O’Reilly book Building Web Apps with WordPress By Brian Messenlehner & Jason Coleman.

The example code can be seen here: see this file on the author’s GitHub.

The problem however is, that we still do not have this Student (extends WP_User, so subclass) available in our code, we still need to instantiate it in the following way to get one Student instance for the current user:

$student = new Student($current_user->ID);

If we do that on a page, the instance will always be created again (hence me referring to the lifecycle in the title) and the call to $student->assignments seems to never be cached inside the WP_User subclass itself after navigating to a new page and/or reloading the page, so for every page load we are hitting the API and database which will probably never perform in our high-traffic production environment.

The $current_user global variable within WordPress itself however (which is an WP_User instance) seems to be created directly after logging in and is then available throughout the whole application as far as my understanding goes. What I really want, is the same availability throughout the application but then for my subclass (Student) instead of the WP_User class, but more importantly, I want to make sure that for every logged in user, the API hit is only done once (just like for $current_user->user_login which is in WP_User for example).

I have also looked into adding user_meta to WP_User, and checked out this question related to it which seemed partially helpful:
Does WordPress cache get_user_meta() results?

However, this is retrieved through wp_cache_get which is WordPress Object Cache which clearly states:

  1. Non-persistent cache is available only during the loading of the current page; once the next page loads, it will be blank once again.
  2. The storage size is limited by the total available memory for PHP on the server. Do not store large data sets, or you might end up with an “Out of memory” message.
  3. Using this type of cache makes sense only for operations repeated more than once in the creation of a page.

We are not using the values in the Student subclass more than once in the creation of the page, however, the value is used on every page in the application once so it would have to be retrieved once for every page load.

Am I just thinking in the wrong direction here, or how would this be possible within WordPress? I really need a good long-term solution here which should perform in a high-traffic production environment. Thanks for all input and help in advance!

3 Answers
3

If I did understand well, we need to cache a value retrieved from another REST service, from the login to logout of the user on the wordpress installation, so we will hook into this wp_login to get the value and cache it using Transient API, Options API or a persistent caching plugin.

add_action('wp_login', 'my_get_and_cache_rest_value');
function my_get_and_cache_rest_value ($user_login, $user) {
    // do your rest call
    // cache it using Transient API, Options API or a persistent caching plugin
}

We can then extend the WP_User object and set a our magic calls to get the data we want from the cache.

class MY_User extends WP_User {
    // no constructor so WP_User's constructor is used

    // method to get cached data
    function getMyCachedData() {
        // get data via my cache solution
        if ( ! isset( $this->data->myData ) )
            $this->data->myData = my_get_cached_data( $this->ID );

        return $this->data->myData;
    }

    // magic method to detect $user->my_data
    function __get( $key ) {
        if ( $key == 'my_data' )
        {
            return $this->getMyCachedData();
        }
        else
        {
            // fallback to default WP_User magic method
            return parent::__get( $key );
        }
    }    
}

I hope this would help someone, and cheers to @Daniel.

Leave a Comment