Shahid Malla

WHMCS Hooks Guide: Extend Functionality Without Modifying Core Files

Shahid Malla Shahid Malla January 4, 2026 15 min read
WHMCS Hooks Guide: Extend Functionality Without Modifying Core Files

WHMCS hooks are the secret weapon of every advanced WHMCS developer. They allow you to execute custom code when specific events occur—without modifying core files that would be overwritten during updates. This guide teaches you everything about hooks, from basic concepts to advanced implementations.

Understanding WHMCS Hooks

Hooks are points in WHMCS's code where you can inject your own functionality. When a specific event occurs (like a client registering or an invoice being paid), WHMCS checks if any hooks are registered for that event and executes them.

Hook Types

WHMCS has two main types of hooks:

  • Action Hooks: Execute code after an event (e.g., send notification after invoice paid)
  • Filter Hooks: Modify data before it's used (e.g., change email content before sending)

Hook File Location

Place your hooks in the /includes/hooks/ directory. Create separate files for different functionalities:

/includes/hooks/
    client_notifications.php
    invoice_automation.php
    order_processing.php

Basic Hook Syntax

The basic structure of a hook uses the add_hook() function:

<?php

add_hook('HookPointName', priority, function($vars) {
    // Your code here
    // $vars contains data related to the hook event
});

The priority parameter (1-99) determines execution order when multiple hooks target the same event. Lower numbers execute first.

ClientAdd - New Client Registration

Execute code when a new client registers:

<?php
add_hook('ClientAdd', 1, function($vars) {
    $clientId = $vars['userid'];
    $email = $vars['email'];
    $firstname = $vars['firstname'];
    
    // Send data to CRM
    $api = new MyCRM();
    $api->createContact([
        'email' => $email,
        'name' => $firstname,
        'source' => 'WHMCS'
    ]);
    
    // Log the action
    logActivity("New client $email synced to CRM");
});

InvoicePaid - Invoice Payment

Trigger actions when an invoice is paid:

<?php
add_hook('InvoicePaid', 1, function($vars) {
    $invoiceId = $vars['invoiceid'];
    
    // Get invoice details
    $invoice = localAPI('GetInvoice', ['invoiceid' => $invoiceId]);
    $amount = $invoice['total'];
    $clientId = $invoice['userid'];
    
    // Send Slack notification for large payments
    if ($amount >= 500) {
        sendSlackNotification(" Large payment received: \$$amount for invoice #$invoiceId");
    }
});

AfterModuleCreate - Service Provisioned

Run code after a hosting account is created:

<?php
add_hook('AfterModuleCreate', 1, function($vars) {
    $serviceId = $vars['serviceid'];
    $domain = $vars['params']['domain'];
    
    // Add to monitoring system
    addToMonitoring($domain);
    
    // Send custom welcome email
    sendCustomWelcomeEmail($serviceId);
});

TicketOpen - Support Ticket Created

React to new support tickets:

<?php
add_hook('TicketOpen', 1, function($vars) {
    $ticketId = $vars['ticketid'];
    $priority = $vars['priority'];
    $subject = $vars['subject'];
    
    // Urgent tickets get Slack alert
    if ($priority == 'High' || stripos($subject, 'urgent') !== false) {
        sendSlackNotification("🚨 Urgent ticket #$ticketId: $subject");
    }
});

Filter Hooks

Filter hooks modify data before WHMCS uses it:

<?php
// Modify email content before sending
add_hook('EmailPreSend', 1, function($vars) {
    $messageName = $vars['messagename'];
    $subject = $vars['subject'];
    $message = $vars['message'];
    
    // Add tracking pixel to all emails
    $trackingPixel = '<img src="https://yoursite.com/track?id=' . $vars['relid'] . '">';
    $message .= $trackingPixel;
    
    return ['message' => $message];
});

ClientAreaPage - Modify Client Area

Add variables to client area templates:

<?php
add_hook('ClientAreaPage', 1, function($vars) {
    // Get current user
    $clientId = $_SESSION['uid'] ?? null;
    
    if ($clientId) {
        // Calculate loyalty discount
        $years = calculateClientYears($clientId);
        $discount = min($years * 2, 20); // 2% per year, max 20%
        
        return [
            'loyaltyYears' => $years,
            'loyaltyDiscount' => $discount
        ];
    }
});

Advanced Hook Techniques

Using localAPI in Hooks

Leverage the internal API for complex operations:

<?php
add_hook('OrderPaid', 1, function($vars) {
    $orderId = $vars['orderId'];
    
    // Get order details via API
    $order = localAPI('GetOrders', ['id' => $orderId]);
    
    // Get client details
    $client = localAPI('GetClientsDetails', ['clientid' => $order['order']['userid']]);
    
    // Process business logic
    processNewOrder($order, $client);
});

Database Operations

Use WHMCS's database abstraction layer:

<?php
use WHMCS\Database\Capsule;

add_hook('DailyCronJob', 1, function($vars) {
    // Find inactive clients
    $inactiveClients = Capsule::table('tblclients')
        ->where('lastlogin', '<', date('Y-m-d', strtotime('-90 days')))
        ->where('status', 'Active')
        ->get();
    
    foreach ($inactiveClients as $client) {
        sendReactivationEmail($client->id);
    }
});

Error Handling

Always implement proper error handling:

<?php
add_hook('InvoicePaid', 1, function($vars) {
    try {
        // Your hook logic
        processPayment($vars['invoiceid']);
    } catch (Exception $e) {
        logActivity("Hook Error: " . $e->getMessage());
        // Optionally notify admin
        sendAdminNotification("Hook failed: " . $e->getMessage());
    }
});

Debugging Hooks

Logging Hook Data

See what data is available in a hook:

<?php
add_hook('ClientAdd', 1, function($vars) {
    logActivity("ClientAdd hook data: " . print_r($vars, true));
    // Now check Activity Log to see all available variables
});

Common Debugging Tips

  • Check syntax errors: Hooks silently fail on PHP errors
  • Verify hook name spelling (case-sensitive)
  • Test with simple logging first
  • Check PHP error logs
  • Use try-catch blocks for all operations

Best Practices

  • Keep hooks focused: One hook file per feature area
  • Document everything: Comments explaining what each hook does
  • Handle errors gracefully: Never let hooks crash WHMCS
  • Test thoroughly: Test in staging before production
  • Monitor performance: Hooks run synchronously—slow hooks slow WHMCS
  • Use queues for heavy operations: Defer API calls to background processes

Conclusion

Hooks transform WHMCS from a standard billing system into a customized automation powerhouse. By mastering hooks, you can integrate WHMCS with any external system, automate complex workflows, and create unique functionality that sets your hosting business apart.

Need custom hooks developed for your specific requirements? I create tailored WHMCS hooks for businesses worldwide, from simple notifications to complex integrations.

Need Custom WHMCS Hooks?

I develop custom hooks for any integration—CRM, Slack, Telegram, accounting software, and more.

Share this article:
Shahid Malla

About Shahid Malla

Expert

Full Stack Developer with 10+ years of experience in WHMCS development, WordPress, and server management. Trusted by 600+ clients worldwide for hosting automation and custom solutions.