Hooks & Architecture
Every WHMCS integration point, plus how the module is built internally.
Hook reference
| Hook | Purpose |
|---|---|
ClientAreaPrimarySidebar / ClientAreaSecondarySidebar | Render the Support PIN sidebar widget (position-controlled). |
ClientAreaPrimaryNavbar | Add the “Support PIN” link to the Support menu. |
UserLogin | Persist/refresh the sub-user PIN permission for the session. |
ClientAreaPage | Register the supportPin sub-user permission. |
ClientAreaHeadOutput / ClientAreaFooterOutput | Inject styles, the permission script and email-preference toggles. |
DailyCronJob / PostAutomationTask | Expire due PINs and remove old expired PINs. |
AdminAreaClientSummaryPage | Show the current PIN card on the WHMCS client summary. |
AdminAreaClientSummaryActionLinks | Link the per-client PIN management page. |
AdminAreaFooterOutput | Add the users-table PIN column, ticket verify button and summary scripts. |
AdminHomeWidgets | Provide a dashboard home widget. |
ClientEdit | Persist per-client email preference opt-outs. |
Directory layout
modules/addons/SupportPin/
├── SupportPin.php # Module entrypoint (config, activate, upgrade, output, clientarea)
├── hooks.php # All WHMCS hook registrations
├── whmcs.json # WHMCS module metadata
├── logo.png # Module logo
├── README.md
├── docs/ # Bundled documentation site
├── lang/
│ └── english.php # Admin + client language strings
├── lib/
│ ├── Admin/
│ │ ├── AdminDispatcher.php # Routes ?p=<page>&a=<action> to controllers
│ │ ├── BaseController.php # Shared view assembly, CSRF, PRG redirects
│ │ ├── DashboardController.php
│ │ ├── PinsController.php
│ │ ├── ClientsController.php
│ │ ├── AuditController.php
│ │ ├── SettingsController.php
│ │ ├── AjaxController.php # Dashboard/ticket verify, mark-used endpoints
│ │ ├── TicketsController.php
│ │ └── VerifyPinWidget.php
│ ├── Client/
│ │ └── PinController.php # Client-area generate/revoke/index actions
│ └── HardSoftCode/
│ ├── SupportPinApi.php # Core domain logic (PIN CRUD, audit, verify)
│ ├── SupportPinRequest.php # Request/CSRF helpers
│ ├── SupportPinTemplates.php
│ └── SupportPinLanguage.php
└── templates/
├── admin/ # Admin Smarty templates + bundled assets
│ ├── dashboard.tpl, pins.tpl, clients.tpl, audit.tpl, settings.tpl
│ ├── verifyform.tpl, verifyresult.tpl, verifywidget.tpl
│ ├── tablelist.tpl, flash.tpl, header.tpl, footer.tpl
│ └── assets/ (css, js, img)
└── client/ # Client-area templates
├── clientarea.tpl, pincode.tpl, sidebar.tpl
├── nopermission.tpl, notloggedin.tpl
Design principles
- OOP controllers — every admin page is a dedicated controller class extending
BaseController, routed byAdminDispatcher. Client actions live inClient\PinControllerand are routed byClientDispatcher. - Core domain in one place — all database access and business rules live in
HardSoftCode\SupportPinApi(static methods), so controllers stay thin and the logic is reusable across admin, client and hooks. - Transactions — every multi-step mutation (
createPin,extendPin,terminatePin,deletePin,expireUsedPin) runs insideCapsule::transaction(). If any step fails, the whole change is rolled back — no half-updated PINs. - PRG (Post-Redirect-Get) — state-changing forms validate the CSRF token, perform the action, flash a message and redirect, preventing duplicate and back-button resubmissions.
- Consistent date handling — all displayed dates pass through WHMCS’
fromMySQLDate()so they respect the admin’s configured timezone and format. - Escaping everywhere — Smarty templates escape output, and dynamic HTML built in PHP (the client summary card, audit labels) uses
htmlspecialchars().
Database tables
| Table | Purpose |
|---|---|
hsc_sp_pins | PIN records: client, user stream, code, status, created/expires timestamps. |
hsc_sp_config | Module settings (PIN length, colour, expiry, sidebar, notifications). |
hsc_sp_audit | Full audit trail of every PIN action. |
hsc_sp_users | Sub-user permission links (client ↔ user). |
hsc_sp_email_prefs | Per-client email preference opt-outs. |
Stable table names — table names use the
hsc_ prefix to remain stable across upgrades and avoid collisions with WHMCS core tables.