Skip to content

Everything Else

The following hooks are provided for Everything Else related events.

AffiliateActivation

Executes as an affiliate is being activated.

Parameters

VariableTypeNotes
affidintThe new unique id for the affiliate (tblaffiliates).
useridint

Response

No response supported

Example Code

<?php
add_hook('AffiliateActivation', 1, function($vars) {
    // Perform hook code here...
});

AffiliateClickthru

Executes when a user has clicked an affiliate referral link.

Parameters

VariableTypeNotes
affiliateIdintThe unique id of the affiliate that the link belongs to

Response

No response supported

Example Code

<?php
add_hook('AffiliateClickthru', 1, function($vars) {
    // Perform hook code here...
});

AffiliateCommission

Executes as affiliate commission is being applied to an affiliate to clear later.

Parameters

VariableTypeNotes
affiliateIdint
referralIdintThe id of the referral
serviceIdintThe id of the referred service
commissionAmountfloatThe amount of commission to be appplied
commissionDelayedboolWill the commission be delayed
clearingDatenullstring
payoutboolWill this commission be applied to the affiliate commissions
messagestringThe reason commission will not be applied if payout is false

Response

Return boolean values to override 'skipCommission' or 'payout'.

Example Code

<?php

//Skip applying the commission for affiliate 2
add_hook('AffiliateCommission', 1, function($vars) {
    $return = [];

    if ($vars['affiliateId'] == 2) {
        $return['skipCommission'] = true;
    }
    return $return;
});


//Ensure commission is applied for affiliate 3
add_hook('AffiliateCommission', 1, function($vars) {
    $return = [];

    if ($vars['affiliateId'] == 3) {
        $return['payout'] = true;
    }
    return $return;
});

AffiliateWithdrawalRequest

Executes when an affiliate withdrawal request is submitted.

Parameters

VariableTypeNotes
affiliateIdintThe unique id of the affiliate making the request
userIdintThe user id of the user making the request
clientIdintThe client id being acted on
balancefloatThe amount of commission the withdrawal request is for

Response

Use the return to skip creating a ticket. Return a boolean value of skipTicket.

Example Code

<?php

//Do not open a ticket for affiliate 2
add_hook('AffiliateWithdrawalRequest', 1, function($vars) {
    $return = [];
    if ($vars['affiliateId'] == 2) {
        $return['skipTicket'] = true;
    }

    return $return;
});

AfterConfigOptionsUpgrade

Executes after a product configurable options upgrade has been processed

Parameters

VariableTypeNotes
upgradeidint

Response

No response supported

Example Code

<?php
add_hook('AfterConfigOptionsUpgrade', 1, function($vars) {
    // Perform hook code here...
});

CCUpdate

Executes after CC details have been stored for a client or the remote storage functions completed.

Parameters

VariableTypeNotes
useridint
cardtypestring
cardnumstringOnly if stored locally
cardcvvstring
expdatestring
cardstartstring
cardissuestring

Response

No response supported

Example Code

<?php
add_hook('CCUpdate', 1, function($vars) {
    // Perform hook code here...
});

CalcAffiliateCommission

Executes as the amount of commission is being calculated

Parameters

VariableTypeNotes
affidint
relidintThe id of the referred service
amountfloatThe amount the commission is being calculated on
commissionfloat

Response

No response supported

Example Code

<?php
add_hook('CalcAffiliateCommission', 1, function($vars) {
    // Perform hook code here...
});

CustomFieldLoad

Executes when custom fields are being loaded

Parameters

VariableTypeNotes
fieldidint
relidintThe related id for the field type.
valuestring

Response

Override the value of the custom field returning the "value" key.

Example Code

<?php

add_hook('CustomFieldLoad', 1, function($vars) {
    return array('value' => 'overridden value',);
});

CustomFieldSave

Executes when custom fields are being saved

Parameters

VariableTypeNotes
fieldidint
relidintThe related id for the field type.
valuestring

Response

Override the value of the custom field returning the "value" key.

Example Code

<?php

add_hook('CustomFieldSave', 1, function($vars) {
    return array('value' => 'overridden value',);
});

EmailPreLog

Runs prior to email being logged.

Parameters

VariableTypeNotes
useridint
datestringCurrent timestamp
tostringComma separated list of recipients
ccstringComma separated list of CC recipients
bccstringComma separated list of BCC recipients
subjectstring
messagestring
attachmentsarray

Response

Accepts a return of key/value pairs to override the parameters to be logged. Use the same names as the input parameters. Return abortLogging to abort logging of the email.

Example Code

<?php

//Do not log emails for userid 2
add_hook('EmailPreLog', 1, function($vars) {
    $return = [];

    if ($vars['userid'] == 2) {
        $return['abortLogging'] = true;
    }

    return $return;
});

//Override the saved subject of the email for userid 3
add_hook('EmailPreLog', 1, function($vars) {
    $return = [];

    if ($vars['userid'] == 3) {
        $return['subject'] = 'This subject is overridden';
    }

    return $return;
});

EmailPreSend

Runs prior to any templated email being sent.

Parameters

VariableTypeNotes
messagenamestringThe name of the email template being sent
relidintThe related entity ID for the email being sent.
mergefieldsarrayOriginal mergefield data

Response

An array of key/value pairs to be made available as additional email template merged fields. To abort the sending, return the key/value pair abortsend=true. To attach a file(s) to the email return an array of the following structure ['attachments'=>[['filename'=>'file1.pdf','data'=>'<file_content_1>'],['filename'=>'file2.png','data'=>'<file_content_2>'],...]].

Example Code

<?php

add_hook('EmailPreSend', 1, function($vars) {
    $merge_fields = [];
    if (!array_key_exists('my_custom_var', $vars['mergefields'])) {
        $merge_fields['my_custom_var'] = "My Custom Var";
        $merge_fields['my_custom_var2'] = "My Custom Var2";
    }
    if ($vars['messagename'] == 'My Message Name' && $vars['relid'] == 2) {
        //Stop the email from sending a specific message and related id.
        $merge_fields['abortsend'] = true;
    }
    $merge_fields['attachments'] = [
        [
            'filename' => 'invoice.pdf',
            'data' => file_get_contents('path/to/file.pdf'),
        ],
    ];

    return $merge_fields;
});

EmailTplMergeFields

Executes when editing an email template.

Parameters

VariableTypeNotes
typestringThe type of email template being edited.

Response

an Array of key -> value pairs of merge fields

Example Code

<?php

//Output additional merge fields in the list when editing an email template
add_hook('EmailTplMergeFields', 1, function($vars) {
    $merge_fields = [];
    $merge_fields['my_custom_var'] = "My Custom Var";
    $merge_fields['my_custom_var2'] = "My Custom Var2";
    return $merge_fields;
});

FetchCurrencyExchangeRates

Executes when updating currency exchange rates. All supported automatic update currencies are returned

Parameters

VariableTypeNotes
USDfloat
GBPfloat

Response

An array of key -> value pairs to define or override additional exchange rates. The rate should be appropriate to the EUR currency.

Example Code

<?php

//Return an exchange rate for the XBT currency
add_hook('FetchCurrencyExchangeRates', 1, function($vars) {
    //Code here to fetch the the current exchange rate relative to EUR

    //Return exchange rate relative to 1 EUR
    return ['XBT' => 927.121,];
});

IntelligentSearch

Executes as the Intelligent Search is being completed

Parameters

VariableTypeNotes
searchTermstringThe term being searched for
numResultsintThe number of results to return

Response

An array of additional search results. See example for array structure. A string response was supported in versions prior to WHMCS 7.7.

Example Code

<?php

add_hook('IntelligentSearch', 1, function ($vars) {
    /**
     * This is an example of array return for an Intelligent Search.
     * This format is supported in the blend WHMCS Admin Template.
     * Any template based on blend and updated to WHMCS 7.7+ is also supported.
     */
    $searchResults = array();

    // look for exact matches in client notes field
    $result = \WHMCS\Database\Capsule::table('tblclients')
        ->where('notes', $vars['searchTerm'])
        ->get();

    foreach ($result as $client) {
        $searchResults[] = [
            'title' => $client->firstname . ' ' . $client->lastname, // The title of the search result. This is required.
            'href' => 'clientssummary.php?userid=' . $client->id, // The destination url of the search result. This is required.
            'subTitle' => $client->email, // An optional subtitle for the search result.
            'icon' => 'fal fa-user', // A font-awesome icon for the search result. Defaults to 'fal fa-star' if not defined.
        ];
    }
    return $searchResults;
});

LinkTracker

Executes when a link.php link is being used.

Parameters

VariableTypeNotes
linkidintThe id of the link being followed

Response

No response supported

Example Code

<?php
add_hook('LinkTracker', 1, function($vars) {
    // Perform hook code here...
});

LogActivity

Executes after an activity log entry has been created.

Parameters

VariableTypeNotes
descriptionstring
userstring
useridint
ipaddressstring

Response

No response supported

Example Code

<?php
add_hook('LogActivity', 1, function($vars) {
    // Perform hook code here...
});

NotificationPreSend

Executes prior to a notification being sent to allow for additional conditional criteria to be applied and manipulation of the notification message.

Parameters

VariableTypeNotes
eventTypestring'Ticket', 'Invoice', 'Order', 'Service', 'Domain', or 'API'
eventNamestring
rule\WHMCS\Notification\RuleNotification rule that has been matched.
hookParametersarray
notification\WHMCS\Notification\Contracts\NotificationInterface

Response

No response supported

Example Code

<?php

add_hook('NotificationPreSend', 1, function($vars) {

    $eventType = $vars['eventType'];
    $eventName = $vars['eventName'];
    $rule = $vars['rule'];
    $hookParameters = $vars['hookParameters'];
    $notification = $vars['notification'];

    // Perform additional conditional logic and throw the AbortNotification
    // exception to prevent the notification from sending.
    if ($eventType == 'Invoice'
        && $eventName == 'created'
        && (isset($hookParameters['invoiceid'])
            && $hookParameters['invoiceid'] > 1000)
    ) {
        throw new \WHMCS\Notification\Exception\AbortNotification();
    }

    // If allowing the notification to continue, you can manipulate the $notification
    // object using the interface, WHMCS\Notification\Contracts\NotificationInterface.
    $notification->setTitle('Override notification title');
    $notification->setMessage('Override notification message body');

});

PayMethodMigration

Executes when legacy payment details are being migrated.

Parameters

VariableTypeNotes
client\WHMCS\User\ClientThe Client Model

Response

A gateway module name.

Example Code

<?php
add_hook('PayMethodMigration', 1, function($vars) {
    // Perform hook code here...
});

PreEmailSendReduceRecipients

Runs prior to a client email being sent and allows selective removal of CC and BCC recipients.

Parameters

VariableTypeNotes
messagenamestringThe name of the email template being sent
relidintThe related entity ID for the email being sent
recipientsarrayArray containing 'cc' and 'bcc' recipients. Each recipient will be an array containing 'email' and 'fullname' indices

Response

An array with a 'cc' and 'bcc' list of recipients. Each recipient in those lists should be indexed with the original index hash as provided by $recipients argument. If an empty 'cc' or 'bcc' list provided, it will remove all 'cc' or 'bcc' recipients respectively. If the 'cc' or 'bcc' is omitted in the return, the original list will remain unaltered

Example Code

<?php
add_hook('PreEmailSendReduceRecipients', 1, function($vars) {
    // Perform hook code here...
});

PreUpgradeCheckout

Executes on checkout of an upgrade order, after the price calculation. The upgrade order may have completed already when this hook runs.

Parameters

VariableTypeNotes
clientIdintThe ID of the client for the upgrade order
upgradeIdintThe ID of the upgrade order
serviceIdintThe ID of the service for the upgrade order
amountfloatThe upgrade order amount. A negative value denotes a credit calculation.
discountfloatThe upgrade order discount.

Response

Return 'amount' and/or 'discount' key with override price for the upgrade order.

Example Code

<?php
add_hook('PreUpgradeCheckout', 1, function($vars) {
    // Perform hook code here...
});

PremiumPriceOverride

Executes when searching for a premium domain. The return can alter the registration & renewal costs, stop the domain being available for purchase or force the client to contact support.

Parameters

VariableTypeNotes
domainNamestring
tldstringeg com in whmcs.com
sldstringeg whmcs in whmcs.com
registerfloatIf a registration, the registration price of the premium domain
transferfloatIf a transfer, the transfer price of the premium domain
renewfloatThe renewal price of the premium domain

Response

Accepts returns to override register, transfer or renew pricing. Also boolean values of noSale or contactUs to stop the sale of the domain with different messages

Example Code

<?php

//Stop the Domain Purchase for this Premium Domain
add_hook('PremiumPriceOverride', 1, function($vars) {
    return ['noSale' => true,];
});

//Force the Client to Contact Support to Purchase Domain
add_hook('PremiumPriceOverride', 1, function($vars) {
    return ['contactUs' => true,];
});

//Override the Register and Renew Pricing & Skip Markup Application
add_hook('PremiumPriceOverride', 1, function($vars) {
    return [
        'register' => 150.00,
        'renew' => 200.00,
        'skipMarkup' => true,
    ];
});

PremiumPriceRecalculationOverride

Executes when a premium domain price is being automatically recalculated.

Parameters

VariableTypeNotes
domainNamestringThe full domain name.
tldstringThe TLD of the domain (E.g. com in whmcs.com)
sldstringThe SLD of the domain (E.g. whmcs in whmcs.com)
renewfloatThe current renewal cost of the domain before any applied markup.

Response

This return is accepted to override the renewal price or skip applying markup. E.g. return array('renew' => 50.00, 'skipMarkup' => true);

Example Code

<?php
add_hook('PremiumPriceRecalculationOverride', 1, function($vars) {
    // Perform hook code here...
});

VatNumberVerification

Verification of a VAT Number.

Parameters

VariableTypeNotes
vatNumber\WHMCS\Billing\VAT\VatNumber

Response

Constant from \WHMCS\Billing\VAT\Verification\VerificationInterface (STATE_VERIFIED, STATE_UNVERIFIED, or STATE_UNKNOWN)

Example Code

<?php
/**
 * Hook for VatNumberVerification must return a verification constant from
 * \WHMCS\Billing\VAT\Verification\VerificationInterface:
 * * STATE_VERIFIED - if the VAT number is registered
 * * STATE_UNVERIFIED - if the VAT number is not registered
 * * STATE_UNKNOWN - if the hook cannot determine the registration state of the
 *   VAT number
 *
 * Multiple hooks may be registered. When a hook responds with STATE_VERIFIED or
 * STATE_UNVERIFIED, the response is treated as authoritative and final.
 * By final:
 *  * when there are multiple hooks are registered, the first authoritative answer
 *    will be yielded to the application, and remaining registered hooks will not
 *    be consulted, and no additional integrated services will be consulted.
 *
 * If neither STATE_VERIFIED nor STATE_UNVERIFIED is yielded after process all
 * registered hooks, STATE_UNKNOWN will be used by the system. When the system
 * uses STATE_UNKNOWN, other integrated services of the system will be polled in
 * an attempt to get an authoritative, final response of STATE_VERIFIED or
 * STATE_UNVERIFIED.
 *
 * Two examples:
 * 1) a hook that uses custom logic for Ireland and Germany and all other EU regions
 * 2) a hook that allows some hypothetical test mode to give results for test numbers
 *
 * While these two could be in one hook, registering both illustrates the pipeline
 * for the verification request.
 */

add_hook('VatNumberVerification', 1, function($vars) {
    /** @var \WHMCS\Billing\VAT\VatNumber $vatNumber */
    $vatNumber = $vars['vatNumber'];
    $isValid = null;

    if ($vatNumber->getPrefix() == 'IE') {
        // Handle Ireland VAT numbers with custom logic
        $number = $vatNumber->getNumber(); // Example: '091234567'

        // custom logic here
        $isValid = customIrelandVatCheck($number);
    } elseif ($vatNumber->getPrefix() == 'DE') {
        // Handle Germany VAT numbers with custom logic
        $isValid = customGermanyVatCheck($vatNumber->getNumber());
    } elseif ($vatNumber->isEU()) {
        // Handle Germany VAT numbers with custom logic
        $isValid = customEuVatCheck($vatNumber->getNumber());
    }

    if ($isValid === false) {
        return \WHMCS\Billing\VAT\Verification\VerificationInterface::STATE_UNVERIFIED;
    } elseif ($isValid === true) {
        return \WHMCS\Billing\VAT\Verification\VerificationInterface::STATE_VERIFIED;
    } else {
        // let any other hook or the system give a final answer
        return \WHMCS\Billing\VAT\Verification\VerificationInterface::STATE_UNKNOWN;
    }
});

add_hook('VatNumberVerification', 1, function($vars) {
    /** @var \WHMCS\Billing\VAT\VatNumber $vatNumber */
    $vatNumber = $vars['vatNumber'];

    if ($someTestModeFlag) {
        if ($vatNumber->getIdentifier() == 'GB123456789') {
            return \WHMCS\Billing\VAT\Verification\VerificationInterface::STATE_VERIFIED;
        } elseif ($vatNumber->getIdentifier() == 'GB987654321') {
            return \WHMCS\Billing\VAT\Verification\VerificationInterface::STATE_UNVERIFIED;
        }
    }

    // let any other hook or the system give a final answer
    return \WHMCS\Billing\VAT\Verification\VerificationInterface::STATE_UNKNOWN;
});