WHMCS Technical Analyst II WHMCS JoshQ Posted September 27, 2023 WHMCS Technical Analyst II Share Posted September 27, 2023 For companies operating hosting infrastructure in multiple countries, it is often desirable to allow the customer to choose where they would like their account to be hosted. There are several ways in which this could be done. One possible solution would be to create separate products for each location, and assign the appropriate Server Group to each one. However, this would mean that you would have to maintain several instances of the same product; if you wanted to update the product in the future, you would have to do so for each instance. Another solution, and the one that I will be covering in this post, is to create one product that allows users to select their location via a Custom Field. This means that all accounts with the same 'plan' are assigned to the same product, which is more streamlined for administrative purposes, and more logical for the end user. However, WHMCS is not able to automatically select the correct location for a new account in this scenario because it doesn't understand the concept of a 'location'. By default, WHMCS can only pick a server from the Server Group assigned under the product's Module Settings - this wouldn't work for this scenario. Therefore we are going to need to write an action hook that can automatically select a server based on the location specified by the client. This guide assumes that you have already added all of your Servers to WHMCS, and that they are all working as expected. Step 1: Create the a new product (and group if applicable) for your hosting plan The first thing that you need to do is create a new product for this hosting plan via System Settings > Products/Services, as per our documentation. Make sure to setup pricing and your module settings according to your requirements. Step 2: Add a new custom field With your product now setup, you should create a new Custom Field for the product called Location. You can do this in the Custom Fields tab in your product settings. Something like the following would work nicely: Step 3: Create the action hook that will assign the correct server In this example, we will only have three servers - one per selectable location. These are: Server ID 1: VPS node in London (UK) Server ID 2: VPS node in Paris (FR) Server ID 3: VPS node in New York (US) Keep in mind that you will need to substitute these IDs with the correct ones for your hosting environment. To achieve the desired outcome, we will be making use of the PreModuleCreate hook, which is called prior to the Create command being run. To get started, create a new file at /includes/hooks called set_serverid_by_location_hook.php With this file created, paste in the following content: <?php add_hook('PreModuleCreate', 1, function($vars) { // Check if the product ID matches a supported product $productId = $vars['pid']; $supportedProducts = array(1, 2, 3); // List of supported product IDs // If it doesn't, do nothing if (!in_array($productId, $supportedProducts)) { return; } // Define serverid and location pairings statically $serverIdMappings = array( 'London (UK)' => '1', 'Paris (FR)' => '2', 'New York (US)' => '3', // Add more location-serverid pairs as needed ); // Get the Location custom field value $location = isset($vars['customfields']['Location']) ? $vars['customfields']['Location'] : ''; // Check if the location is supported if (!isset($serverIdMappings[$location])) { logActivity("Server ID not found for location: $location"); return; } // Override parameters for account creation return array( 'serverid' => $serverIdMappings[$location], // Add any other parameters you want to override here ); }); ?> This script will set the server ID based on the Location defined by the customer. If you have multiple servers per location and want to assign one randomly, then the above will need to be modified slightly. Something like this should do the trick (the modified sections have comments - the other parts do not): <?php add_hook('PreModuleCreate', 1, function($vars) { $productId = $vars['pid']; $supportedProducts = array(1, 2, 3); if (!in_array($productId, $supportedProducts)) { return; } // Define serverid and location pairings // This time, there can be multiple server IDs per location. $serverIdMappings = array( 'London (UK)' => array('serverid1', 'serverid2', 'serverid3'), // Multiple server IDs for London 'Paris (FR)' => array('serverid4', 'serverid5'), // Multiple server IDs for Paris 'New York (US)' => array('serverid6', 'serverid7'), // Multiple server IDs for New York // Add more location-serverid pairs as needed ); $location = isset($vars['customfields']['Location']) ? $vars['customfields']['Location'] : ''; if (!isset($serverIdMappings[$location])) { logActivity("Server IDs not found for location: $location"); return; } // Get a random server ID from the list of server IDs for the location $randomServerId = $serverIdMappings[$location][array_rand($serverIdMappings[$location])]; return array( 'serverid' => $randomServerId, ); }); ?> The result of this will be that the server is provisioned in the appropriate location at the time of module creation. Keep in mind that changing the value of the Location field will not update the location of the account. To do this, you will need to migrate the account to the new server. The above code worked at the time of writing. Please keep in mind that this is a customisation to WHMCS, and as such our Support team won't be able to troubleshoot any issues that you encounter with it - this extends beyond the remit of our support package. Any questions or feedback on the above are always welcome. 2 Quote Link to comment Share on other sites More sharing options...
PascM Posted October 4, 2023 Share Posted October 4, 2023 Nice! I'd love to see that in WHMCS as native support! 1 Quote Link to comment Share on other sites More sharing options...
Saleem007 Posted October 17, 2023 Share Posted October 17, 2023 Hey, thanks for the solution. I tried following the guide and the code but it appears it's partially not working. For example, I order product 1, selected location 1, and it launched on location 1. And when ordering again, product 1 and location 1, it launches account on location 2. And then ordering again follows the pattern. One time it's location 1, then location 2, then again location 1, and then location 2, and so on regardless of the chosen location. Here's the code I tried modifying with debugging. <?php add_hook('AfterModuleCreate', 1, function($vars) { // Debugging: Log information to help diagnose the issue logActivity("Debugging: Hook triggered for product ID: " . $vars['params']['pid']); // Check if the product ID matches a supported product $productId = $vars['params']['pid']; $supportedProducts = array(1, 2, 4, 5, 6); // List of supported product IDs // Debugging: Log the product ID to check if it's correct logActivity("Debugging: Product ID is $productId"); // If it doesn't, do nothing if (!in_array($productId, $supportedProducts)) { return; } // Define serverid and location pairings statically $serverIdMappings = array( 'West Cost (US)' => '1', 'Germany (EU)' => '2', // Add more location-serverid pairs as needed ); // Get the Location custom field value $location = isset($vars['params']['customfields']['Location']) ? $vars['params']['customfields']['Location'] : ''; // Debugging: Log the location value to check if it's correct logActivity("Debugging: Location is $location"); // Check if the location is supported if (!isset($serverIdMappings[$location])) { logActivity("Debugging: Server ID not found for location: $location"); return; } // Debugging: Log the selected server ID logActivity("Debugging: Selected Server ID is {$serverIdMappings[$location]}"); // Override parameters for account creation return array( 'serverid' => $serverIdMappings[$location], // Add any other parameters you want to override here ); }); ?> Then, I checked the ActivityLog and it's showing correct values as chosen. Debugging: Hook triggered for product ID: 1 Debugging: Product ID is 1 Debugging: Location is West Cost (US) Debugging: Selected Server ID is 1 But, it launched the cPanel account on Server ID 2 (Germany). And, here are my settings for Product 1 Any solution please? 0 Quote Link to comment Share on other sites More sharing options...
Saleem007 Posted November 15, 2023 Share Posted November 15, 2023 Hello joshq, I think I caught the issue. The reason could be that in Servers -> Group, the Fill Type is set to "Add to the least full server" and the other option is "Fill active server until full then switch to next least used". But the script is not overriding the Fill Type and forcing users to follow the Fill Type regardless of the user selected location. Is there a way to override Fill Type and enforce what user has been selected? 0 Quote Link to comment Share on other sites More sharing options...
Gianni Posted December 9, 2023 Share Posted December 9, 2023 Hello, guys. I tried the script, but it doesn't work. Like said @Saleem007, the script don't override the file type and always use the default server. 0 Quote Link to comment Share on other sites More sharing options...
semden Posted March 4, 2024 Share Posted March 4, 2024 Any solutions, how to get this works? We even ready to pay 🙂 0 Quote Link to comment Share on other sites More sharing options...
withfaith Posted March 16, 2024 Share Posted March 16, 2024 Hi everyone, Anyone know if a similar approach is available to select Server Group based on custom field? The above looks like its selecting the Server ID directly, would want to just select the Server Group and let WHMCS do the job selecting. (Fill Least Full) 0 Quote Link to comment Share on other sites More sharing options...
Achievement In Motion Posted April 18, 2024 Share Posted April 18, 2024 Whats the best method to just show the server ping prior to choosing and allow the client to make their final choice? 0 Quote Link to comment Share on other sites More sharing options...
RadWebHosting Posted April 19, 2024 Share Posted April 19, 2024 13 hours ago, Achievement In Motion said: Whats the best method to just show the server ping prior to choosing and allow the client to make their final choice? Could provide a test IP address with each stated server locale. I.E.: US - 10.10.10.10 NL - 10. 11.11.11 BR - 10.12.12.12 0 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.