We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 17301
    • 932 Posts
    Please note there are some caveats at the bottom regarding using two registration systems and some issues that may present themselves.

    WHMCS is a really powerful system for helping you to run your business, but if your site already has an exisiting login and registration system it can be an annoyance for your users to have to login twice into two different systems. Using the WHMCS API it is possible to externally register and login your users though and the requirements to get this working with MODX is actually minimal.

    The complexity came in that the decrypt password API call from WHMCS didn't work as expected (at the time of writing this post, atleast) and so it took a fair few days of digging around and trial and error to get this work.

    So assuming that you already have a login and registration system setup in MODX, utilising the Login extra we need to create two snippets that will act as hooks. One to handle registrations for both systems and one to handle the logins.

    Before we get started however you'll need to get your API keys for WHMCS in admin/configapicredentials.php, or by navigating to setup > staff management > manage api credentials. This option is only available in version 7.2+ and if you don't have it or can't update your version of WHMCS then you'll need to use your admin username and password in your snippets instead.

    Starting with Registrations you'll need to create a snippet called 'WHMCS_Register'. WHMCS requires a certain amount of information in order to succesfully register a user, therefore you'll need to ensure that your MODX registration form and database takes into account all of the required fields that are dictated on this webpage as a bare minimum.
    https://developers.whmcs.com/api-reference/addclient/
    In the snippet below I am also storing a value of 'clientid' which is the ID number assigned to clients in WHMCS. This is important, and needed, to use additional API calls that are specific to a user (such as forgot password, display invoices etc). You'll need to ensure you've created this field also.
    I've opted to use BobRays classextender (see: https://modx.com/extras/package/classextender) to quickly extend the user object to accomodate for the additional fields.

    WHMCS_Register

    <?php
    // API Connection Details
    $whmcsUrl = "https://*****.*****.co.uk/"; // the subdomain or folder where you've installed WHMCS
    $api_identifier = '*****'; // Your API Identifier
    $api_secret = '*****'; // Your API Secret Key
    
    // Grab Form Values
    $user = $modx->getObject('modUser', array('username'=>$hook->getValue('email')));
    $pass = $hook->getValue('password');
    $email = $hook->getValue('email');
    
    $modx->loadClass('userData',MODX_BASE_PATH . 'core/components/classextender/model/extendeduser/');
    if (isset($user) && ($user instanceof  modUser)) {
      $data = $modx->getObject('userData', array('userdata_id' => $user->get('id')));
    }
    if (!$data) {
      $data = $modx->newObject('userData');
    }
    
    $data->set('userdata_id', $user->get('id'));
    
    // Set post values
    $postfields = array(
      'action' => 'AddClient',
      'username' => $api_identifier,
      'password' => $api_secret,
      'firstname' => $hook->getValue('firstName'),
      'lastname' => $hook->getValue('lastLame'),
      'email' => $email,
      'address1' => $hook->getValue('address'),
      'city' => $hook->getValue('city'),
      'state' => $hook->getValue('state'),
      'postcode' => $hook->getValue('zip'),
      'country' => $hook->getValue('country'), 
      'phonenumber' => $hook->getValue('mobilephone'),
      'password2' => $pass,
      'responsetype' => 'json',
      );
    
    // Call the API
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $whmcsUrl . 'includes/api.php');
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_TIMEOUT, 30);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postfields));
    $response = curl_exec($ch);
    if (curl_error($ch)) {
      die('Unable to connect: ' . curl_errno($ch) . ' - ' . curl_error($ch));
    }
    curl_close($ch);
    
    // Decode response
    $jsonData = json_decode($response, true);
    
    if($jsonData['result']=='error'){
      $modx->log(modX::LOG_LEVEL_ERROR,'Error in WHMMC registration for user '.$user->get('id').' '.$email.' : '.$jsonData['message']);
    } else {
      $data->set('clientid', $jsonData['clientid']);
    }
    
    $data->save();
    
    return true;


    In your Register call on your registration page you'll now need to call the snippet as a posthook.
    Please also note that the user is activated by default in WHMCS, so you may wish to also remove the required activation in MODX also or write some additional code that won't register the user in WHMCS until the user has become activated in MODX.

    [[!Register?
    ...
    &postHooks=`WHMCS_Register`
    &usernameField=`email`
    &activation=`0`
    &autoLogin=`1`
    ...
    ]]
    


    Assuming everything has been setup correctly if you now register through MODX you should also see the user listed in your WHMCS administration under the list clients page. We can now move on to dealing with logging the users into both systems.

    It turns out, that it is possible to authorise users from an external third party (trusted) source using autoauth in WHMCS. (See: https://docs.whmcs.com/AutoAuth) This however is NOT listed in the API documentation but it is available in the main documentation *rips hair out*. The API does have a series of calls to enable you to log a user in via the API but for all intensive purposes this didn't work as you'd expect and there was some issues with the decrypt password function. Using the autoauth method however does seem to work well.

    So assuming you've followed the above documentation you just need to set an autoauthkey in your WHMCS config file and then simply create a snippet called 'WHMCS_Login'. Within my snippet below you'll see that I've also created a file called redirectme.php which simply redirects the user either back to MODX to display a custom dashboard resource - this is optional and you can set the $goto variable to land elsewhere within WHMCS if needed.

    WHMCS_Login

    <?php
    /*
     WHMCS AutoAuth Demo Script
     Docs: http://docs.whmcs.com/AutoAuth
     */
     
     # Grab Username
     $username = $hook->getValue('username');
     
     # Define WHMCS URL & AutoAuth Key
     $whmcsurl = "http://*****.*****.uk/dologin.php";
     $autoauthkey = "*****"; // The autoauth key that you set
     
     $timestamp = time(); # Get current timestamp
     $email = $username; # Clients Email Address to Login
     $goto = "redirectme.php";
     
     $hash = sha1($email.$timestamp.$autoauthkey); # Generate Hash
     
     # Generate AutoAuth URL & Redirect
     $url = $whmcsurl."?email=$email×tamp=$timestamp&hash=$hash&goto=".urlencode($goto);
     header("Location: $url");
     exit;


    The last step is to simply add the postHook to your Login call.

    [[!Login? 
       ...
       &postHooks=`WHMCS_Login`
       ...
    ]]
    


    Caveats: So with two registration systems comes its own problems such as how do you handle forgotten passwords? resetting passwords and so on. If you've gone down this road of wanting to use MODX to handle registrations and logins then you do need to continue down this road and let MODX also handle password management. This does mean that you'll need to strip these links from your WHMCS template and ideally setup a redirect for those specific pages to go to the MODX equivalents. You'll also then need to create custom snippets as above using the other API methods of updating a profile, resetting a password and any other eventuality that may be problematic.
    [ed. note: lkfranklin last edited this post 6 years, 9 months ago.]
      ■ email: [email protected] | ■ website: https://alienbuild.uk

      The greatest compliment you can give back to us, is to spend a few seconds leaving a rating at our trustpilot: https://uk.trustpilot.com/review/alienbuild.uk about the service we provided. We always drop mention of services offered by businesses we've worked with in the past to those of interest.
      • 3749
      • 24,544 Posts
      Thanks for posting that. I'm sure that will help others.:)

      FYI, you may already know this, but there are two unused fields in the modUser object:

      remote_key  (string)
      remote_data (json)


      It might be possible to use these to avoid having to extend the modUser object.
        Did I help you? Buy me a beer
        Get my Book: MODX:The Official Guide
        MODX info for everyone: http://bobsguides.com/modx.html
        My MODX Extras
        Bob's Guides is now hosted at A2 MODX Hosting
        • 17301
        • 932 Posts
        Haha excellent, thank you again Bob smiley That will certainly come in handy for this and a ton of other things going forwards!
          ■ email: [email protected] | ■ website: https://alienbuild.uk

          The greatest compliment you can give back to us, is to spend a few seconds leaving a rating at our trustpilot: https://uk.trustpilot.com/review/alienbuild.uk about the service we provided. We always drop mention of services offered by businesses we've worked with in the past to those of interest.