WHMCS Module Development Tutorial 2026: Build Your First Module
WHMCS Module Development Tutorial 2026: Build Your First Module
Learn how to develop WHMCS modules from scratch in this comprehensive 2026 tutorial. We'll cover module structure, database operations, admin interfaces, and deployment best practices.
Introduction to WHMCS Module Development
WHMCS modules extend functionality without modifying core files. Types of modules include:
- Addon Modules: Additional features and tools
- Server Modules: Integration with hosting panels
- Gateway Modules: Payment processing
- Registrar Modules: Domain registration
Prerequisites
- PHP knowledge (OOP, PDO, namespaces)
- WHMCS installation for testing
- Text editor or IDE
- Basic understanding of databases
Module Structure
Basic Directory Structure
your_module/
├── your_module.php (main module file)
├── admin/
│ └── index.php (admin interface)
├── client/
│ └── index.php (client area)
├── includes/
│ └── functions.php (helper functions)
└── templates/
├── admin.tpl (admin template)
└── client.tpl (client template)
Step 1: Create Module File
Basic Addon Module Structure
<?php
if (!defined("WHMCS")) {
die("This file cannot be accessed directly");
}
function your_module_config() {
return array(
"name" => "Your Module Name",
"description" => "Module description",
"version" => "1.0",
"author" => "Your Name",
"language" => "english",
"fields" => array(
"option1" => array(
"FriendlyName" => "Option 1",
"Type" => "text",
"Size" => "25",
"Description" => "Enter option 1 value"
)
)
);
}
function your_module_activate() {
// Create database tables
$query = "CREATE TABLE IF NOT EXISTS `mod_your_module` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`setting` VARCHAR(255) NOT NULL,
`value` TEXT,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;";
full_query($query);
return array("status" => "success", "description" => "Module activated successfully");
}
function your_module_deactivate() {
// Optional: Clean up on deactivation
return array("status" => "success", "description" => "Module deactivated");
}
function your_module_output($vars) {
// Client area output
return "<p>Welcome to Your Module</p>";
}
function your_module_clientarea($vars) {
// Client area function
return array(
"pagetitle" => "Your Module",
"breadcrumb" => array("Your Module" => ""),
"templatefile" => "client",
"vars" => array(
"message" => "Hello from Your Module"
)
);
}
function your_module_adminarea($vars) {
// Admin area function
return array(
"pagetitle" => "Your Module Admin",
"breadcrumb" => array("Your Module" => ""),
"templatefile" => "admin",
"vars" => array()
);
}
?>
Step 2: Database Operations
Creating Tables
function your_module_activate() {
$query = "CREATE TABLE IF NOT EXISTS `mod_your_module_data` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`user_id` INT(11) NOT NULL,
`data` TEXT,
`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;";
full_query($query);
return array("status" => "success");
}
Using Capsule (WHMCS Database Class)
use WHMCS\Database\Capsule;
// Insert data
Capsule::table("mod_your_module_data")->insert([
"user_id" => $userid,
"data" => $data
]);
// Query data
$results = Capsule::table("mod_your_module_data")
->where("user_id", $userid)
->get();
// Update data
Capsule::table("mod_your_module_data")
->where("id", $id)
->update(["data" => $newData]);
// Delete data
Capsule::table("mod_your_module_data")
->where("id", $id)
->delete();
Step 3: Admin Interface
Admin Template (admin.tpl)
{if $smarty.get.action == "settings"}
<form method="post" action="addonmodules.php?module=your_module&action=save">
<div class="form-group">
<label>Setting 1</label>
<input type="text" name="setting1" value="{$setting1}" class="form-control">
</div>
<button type="submit" class="btn btn-primary">Save</button>
</form>
{else}
<h2>Your Module Admin</h2>
<p>Welcome to the admin area</p>
<a href="addonmodules.php?module=your_module&action=settings" class="btn btn-default">Settings</a>
{/if}
Step 4: Client Area Interface
Client Template (client.tpl)
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Your Module</h3>
</div>
<div class="panel-body">
<p>{$message}</p>
<!-- Your client area content -->
</div>
</div>
Step 5: Using WHMCS API
Local API Calls
// Get client details
$result = localAPI("GetClientsDetails", array(
"clientid" => $clientid
));
// Create invoice
$result = localAPI("CreateInvoice", array(
"userid" => $userid,
"date" => date("Y-m-d"),
"duedate" => date("Y-m-d", strtotime("+30 days")),
"itemdescription1" => "Service Fee",
"itemamount1" => "10.00"
));
// Send email
sendMessage("Template Name", $userid, array(
"customvar" => $value
));
Step 6: Hooks Integration
Registering Hooks
add_hook("InvoicePaid", 1, function($vars) {
$invoiceId = $vars["invoiceid"];
// Your custom logic here
logActivity("Invoice #" . $invoiceId . " paid");
});
Step 7: Security Best Practices
Input Validation
// Always validate and sanitize input
$userid = (int)$_POST["userid"];
$data = trim($_POST["data"]);
// Use prepared statements
$stmt = Capsule::connection()->getPdo()->prepare(
"SELECT * FROM mod_your_module WHERE id = ?"
);
$stmt->execute([$id]);
$result = $stmt->fetch();
Permission Checks
// Check admin permissions
if (!function_exists("checkPermission")) {
require_once("../../../includes/adminfunctions.php");
}
if (!checkPermission("your_module", "access")) {
die("Access denied");
}
Step 8: Testing Your Module
Testing Checklist
- ✅ Module activates without errors
- ✅ Database tables created correctly
- ✅ Admin interface loads
- ✅ Client area displays
- ✅ API calls work
- ✅ Hooks execute properly
- ✅ Error handling works
- ✅ Module deactivates cleanly
Step 9: Deployment
Packaging Your Module
- Create ZIP file with all module files
- Include installation instructions
- Add changelog
- Test installation on clean WHMCS
Version Control
function your_module_config() {
return array(
"name" => "Your Module",
"version" => "1.0.0", // Use semantic versioning
// ...
);
}
Common Development Patterns
Configuration Management
// Get module configuration
$config = getModuleConfig("your_module");
// Save configuration
updateModuleConfig("your_module", array(
"setting1" => $value1,
"setting2" => $value2
));
Error Handling
try {
// Your code
$result = someFunction();
} catch (Exception $e) {
logModuleCall("your_module", "function_name", $vars, "", $e->getMessage(), array());
return array("error" => $e->getMessage());
}
Advanced Features
Cron Jobs
function your_module_cron() {
// Your cron job code
logActivity("Your Module Cron: Executed");
}
AJAX Support
// In your module file
if ($_GET["ajax"] == "1") {
header("Content-Type: application/json");
echo json_encode(array("status" => "success"));
exit;
}
WHMCS 8.x Development Notes
- Use namespaces for better code organization
- Leverage new API features
- Follow PSR coding standards
- Use dependency injection where possible
Resources and Documentation
- WHMCS Developer Documentation
- WHMCS API Reference
- WHMCS Hooks Documentation
- WHMCS Community Forums
Conclusion
Developing WHMCS modules requires understanding of PHP, WHMCS architecture, and best practices. Start with simple modules and gradually add complexity. Always test thoroughly before deployment.
Need help with WHMCS module development? Check out our premium WHMCS modules for examples and inspiration, or contact us for custom development services.