WordPress – Some Lessons Learned

As you’ve read before in this blog, I’m working on some plugins to display genealogy data on a WordPress site. I have a plugin for Gramps (written in Python) that creates data files, and a plugin for WordPress (written in PHP) to present that data. This currently requires the webmaster to manually copy the resulting files to the server. The next step in the development process is to make the Gramps plugin communicate directly with the WordPress plugin to update the data.

This is one of the most ambitious projects I’ve embarked on as a hobby programmer. I spent the past few days getting up to speed on programming the WordPress REST API. The last hurdle to get past was interesting. The REST API requires creating a nonce, and passing it on all API calls to the server. Since my code needs to update data on the server, these API calls must be in the context of a logged-in session. The first step in the process must, however, be allowed for a not logged-in user since it logs the user into the server.

The problem is that the value of the nonce is determined based on the session cookie, and that cookie is different for a logged-in session and a not logged-in session. I struggled for a while to try to figure out how I could create a nonce for the logged-in session while performing a function in a not logged-in session.

After a few days of trying different things, searching on-line, and at times spinning my wheels, I finally found that one source on-line that explained the solution. Here’s my working signon function code with the necessary code in bold:

function my_update_cookie($logged_in_cookie) {
    $_COOKIE[LOGGED_IN_COOKIE] = $logged_in_cookie;
}

function tangled_web_start(WP_REST_Request $request) {
    add_action('set_logged_in_cookie', 
               [$this, 'my_update_cookie']);

    $creds = ['user_login' => 
                   $request->get_param('id'),
              'user_password' => 
                   $request->get_param('pw'),
              'remember' => true];

    $user = wp_signon($creds, false);
    if (is_wp_error($user)) {
        return $user;
    }

    wp_set_current_user($user->ID);
    wp_set_auth_cookie($user->ID);
    return wp_create_nonce('wp_rest');
} 

The key is to add the 'set_logged_in_cookie' action. Once the signon takes place, that action is called and the LOGGED_IN_COOKIE is updated. Once that is done, the correct nonce is then created.

On the python side, the session issues are managed by an instance of the requests.Session() class. Here’s how the call to the above API is done:

# Logon to WordPress site
session = requests.Session()
parms = {'id': logon_creds['userid'],
         'pw': logon_creds['password']}
res = session.post(url=tgturl + 
                   wp-json/tangled_web/start',
                   data=parms);
if res.status_code != 200:
    return 'Login failed'
nonce = res.text
session.headers.update({'X-WP-Nonce': nonce})

Once the nonce is returned, it gets added to the headers for all subsequent API calls.

Now that I’ve got this working, the rest of the development process should be relatively straight-forward. I’ll have to program API’s for the following tasks:

  • Get a list of checksums for the JSON data files on the servers for a given Tangled Web instance
  • Upload a JSON file or image file to the server
  • Update the names index on the server
  • Update the global settings for the instance

Once this is done, my usual Gramps workflow will have one more step. At the end of a session adding and updating people in my Gramps database, I’ll be able to invoke the “Export to Tangled Web” function in Gramps to update the server immediately, instead of having to manually copy and unpack the files on the server and reload the data.

Leave a Reply