How can we help you today?

WHMCS – Easily Allow Subdomains in WHMCS (The “Own Domain” Bypass)

Introduction

If you run a web hosting business using WHMCS, you have likely encountered clients who want to use an existing subdomain (like blog.theircompany.com) when signing up for a new hosting package.

By default, WHMCS explicitly blocks this. If a user selects “I will use my existing domain and update my nameservers” and types a subdomain into the input field, they are instantly hit with a red error message: “The domain is invalid.

In this guide, we will look at why WHMCS does this and how to completely bypass the restriction using a simple, update-safe trick.

The Problem: The WHMCS AJAX Wall

In modern versions of WHMCS, domain validation on the order form is incredibly strict.

When a user types a domain and clicks “Use”, WHMCS triggers a background AJAX request to its core validation scripts. This script evaluates the structure of the input. If it detects a dot (.) inside the Second-Level Domain (SLD) field, it flags it as an invalid apex domain and halts the checkout process entirely.

Because this validation is hardcoded into WHMCS’s compiled JavaScript assets, you cannot easily override it with a standard PHP validation hook. The frontend script will block the submission before your server even gets a chance to look at it.

The Solution: The “Smuggler” Method

To beat the frontend validator without hacking core system files, we need to temporarily trick the browser into thinking the user typed a standard domain, and then quietly fix it on the backend before the invoice is generated.

We do this in two simple steps:

  1. Frontend: A tiny JavaScript snippet intercepts the user’s click and replaces the dot with the letters xdotx (e.g., blog.test becomes blogxdotxtest). WHMCS approves this format and sends it to the cart.
  2. Backend: A PHP hook detects xdotx in the cart session and silently restores the dot so the hosting account provisions correctly.

Here is how to implement it on your WHMCS installation.

Step 1: The Frontend Smuggler (JavaScript)

First, we need to modify your active order form template to include our intercept script.

  1. Navigate to your WHMCS template directory: /templates/orderforms/standard_cart/ (replace standard_cart if you use a custom theme).
  2. Open the configureproductdomain.tpl file.
  3. Scroll to the very bottom of the file and paste the following code right below the final closing tag:
<script>
$(document).ready(function() {
    // Listen for the click on the "Use" button for existing domains
    $('#useOwnDomain').on('click', function() {
        var sldInput = $('#owndomainsld');
        
        // If they typed a dot, replace it with pure letters so the strict validator passes it
        if (sldInput.val().indexOf('.') !== -1) {
            sldInput.val(sldInput.val().replace(/\./g, 'xdotx'));
        }
    });
});
</script>

Save and close the file.

Step 2: The Backend Restorer (PHP)

Now we need to tell WHMCS to clean up the data once it reaches the server. We will use the PreCalculateCartTotals hook so it updates instantly in the sidebar summary.

Paste the following code into the file:

  • Navigate to your WHMCS hooks directory: /includes/hooks/
  • Create a new PHP file named allow_subdomains.php.
  • Paste the following code into the file:
<?php
// /includes/hooks/allow_subdomains.php

if (!defined("WHMCS")) {
    die("This file cannot be accessed directly");
}

// PreCalculateCartTotals fires every time the cart updates, even via AJAX
add_hook('PreCalculateCartTotals', 1, function($vars) {
    // Check if there are hosting products in the cart
    if (isset($_SESSION['cart']['products']) && is_array($_SESSION['cart']['products'])) {
        foreach ($_SESSION['cart']['products'] as $key => $product) {
            // If the domain contains our smuggler string
            if (!empty($product['domain']) && strpos($product['domain'], 'xdotx') !== false) {
                // Swap it back to a dot instantly inside the session
                $_SESSION['cart']['products'][$key]['domain'] = str_replace('xdotx', '.', $product['domain']);
            }
        }
    }
});

Save the file. Because this is placed in the /hooks/ directory, WHMCS will load it automatically.

Step 3: Clear Your Template Cache

WHMCS aggressively caches template files (.tpl). Your new JavaScript will not execute for your users until you clear this cache.

You can clear the cache via the WHMCS Admin Area:

  • Navigate to Configuration (Wrench Icon) > System Settings > Utilities > System > Clear Templates Cache.

Alternatively, you can clear it via your server terminal using SSH:

rm -rf /path/to/whmcs/templates_c/*

Summary

When a client types blog.test into the domain field and clicks Use, the script instantly formats it to blogxdotxtest. The strict WHMCS frontend validator gives it a green light and pushes the user to the product configuration screen.

Before the page even fully loads, the PHP hook fires in the background, restoring the domain to its proper blog.test.com format. The client checks out seamlessly, and your server provisions the account with the correct hostname!

If you like this article we have plenty more available here.

Leave a Reply

Your email address will not be published. Required fields are marked *

    ICTU LTD is a company registered England and Wales (Company No. 09344913) 142 Thornes Lane, Wakefield, England, WF2 7RE
    Copyright © 2025 ICTU LTD, All Rights Reserved.