update v1.2.5

This commit is contained in:
Yuri Karamian
2026-07-15 00:03:43 +02:00
parent fc2d2d4df6
commit 7a19e78d51
4 changed files with 138 additions and 51 deletions
+18 -9
View File
@@ -59,7 +59,7 @@ WHMCS server module for Hetzner Cloud VPS management.
- Server Type: `cx23`, `cx33`, `cx43`, `cx53` (Cost-Optimized), `cpx11`, `cpx21`, `cax11`, `ccx13`, etc. - Server Type: `cx23`, `cx33`, `cx43`, `cx53` (Cost-Optimized), `cpx11`, `cpx21`, `cax11`, `ccx13`, etc.
- Operating System: `ubuntu-22.04`, `debian-11`, `rocky-9`, etc. - Operating System: `ubuntu-22.04`, `debian-11`, `rocky-9`, etc.
- Datacenter: `fsn1`, `nbg1`, `hel1`, `ash`, `hil`, `sin` - Location: `fsn1`, `nbg1`, `hel1`, `ash`, `hil`, `sin`
- Backups: On/Off - Backups: On/Off
- Create Floating IP: On/Off - Create Floating IP: On/Off
- Cloud-Init YAML: Optional custom cloud-init configuration - Cloud-Init YAML: Optional custom cloud-init configuration
@@ -84,17 +84,19 @@ Create in Setup → Products/Services → Configurable Options:
- `No|None` - `No|None`
- `Yes|1 Floating IP` - `Yes|1 Floating IP`
**2\. Datacenter Selection** **2\. Location Selection**
- Option Name: `datacenter` - Option Name: `Location`
- Option Type: `Dropdown` - Option Type: `Dropdown`
- Options: - Options:
- `fsn1-dc14|Falkenstein, Germany` - `fsn1|Falkenstein, Germany`
- `nbg1-dc3|Nuremberg, Germany` - `nbg1|Nuremberg, Germany`
- `hel1-dc2|Helsinki, Finland` - `hel1|Helsinki, Finland`
- `ash-dc1|Ashburn, USA` - `ash|Ashburn, USA`
- `hil-dc1|Hillsboro, USA` - `hil|Hillsboro, USA`
- `sin-dc1|Singapore, Singapore` - `sin|Singapore, Singapore`
Existing configurable options named `datacenter` remain supported. Legacy values such as `fsn1-dc14` are automatically converted to their corresponding location (`fsn1`) when provisioning.
**3\. Server Type** **3\. Server Type**
@@ -329,6 +331,13 @@ Check out our other WHMCS modules at [arkhost.com/whmcs-modules.php](https://ar
## Changelog ## Changelog
### v1.2.5
**Fixed:**
- Restored server provisioning after Hetzner removed the deprecated `datacenter` request property on July 1, 2026
- Replaced datacenter discovery with the Hetzner Locations API
- Updated client-area location display for the current server response format
- Added automatic conversion of legacy datacenter values such as `fsn1-dc14` to `fsn1`
### v1.2.4 ### v1.2.4
**Fixed:** **Fixed:**
- IP address now stored on the service at provisioning (and backfilled for existing services) so it displays in WHMCS instead of showing blank - IP address now stored on the service at provisioning (and backfilled for existing services) so it displays in WHMCS instead of showing blank
@@ -3,7 +3,7 @@
* WHMCS Server Module - Hetzner VPS * WHMCS Server Module - Hetzner VPS
* *
* @package WHMCS * @package WHMCS
* @version 1.2.4 * @version 1.2.5
* @copyright Copyright (c) ArkHost 2025 * @copyright Copyright (c) ArkHost 2025
* @author ArkHost <support@arkhost.com> * @author ArkHost <support@arkhost.com>
* @link https://arkhost.com * @link https://arkhost.com
@@ -104,6 +104,57 @@ function ArkHostHetznerVPS_GetConfigurableOption(array $params, $optionName) {
return null; return null;
} }
/**
* Convert a legacy Hetzner datacenter name (for example fsn1-dc14) to the
* corresponding location name (fsn1). Location names are normalized to
* lowercase, while numeric IDs remain unchanged.
*/
function ArkHostHetznerVPS_NormalizeLocation($location) {
if (!is_scalar($location)) {
return '';
}
$location = trim((string)$location);
if ($location === '') {
return '';
}
if (preg_match('/^([a-z0-9]+)-dc[0-9]+$/i', $location, $matches)) {
return strtolower($matches[1]);
}
return strtolower($location);
}
/**
* Resolve the server location while remaining compatible with configurable
* options named either "Location" or the former "Datacenter".
*/
function ArkHostHetznerVPS_GetLocationOption(array $params, $default = NULL) {
foreach (array('configoptions', 'customfields') as $collection) {
if (!isset($params[$collection]) || !is_array($params[$collection])) {
continue;
}
// Prefer the current option name if both current and legacy options
// happen to exist on the same product.
foreach (array('location', 'datacenter') as $optionName) {
foreach ($params[$collection] as $name => $value) {
$normalizedName = strtolower(trim((string)$name));
if ($normalizedName === $optionName && $value !== '') {
return ArkHostHetznerVPS_NormalizeLocation($value);
}
}
}
}
// Keep using the original module setting key so existing WHMCS products
// retain their configoption3 value after upgrading.
return ArkHostHetznerVPS_NormalizeLocation(
ArkHostHetznerVPS_GetOption($params, 'datacenter', $default)
);
}
function ArkHostHetznerVPS_API(array $params) { function ArkHostHetznerVPS_API(array $params) {
$url = 'https://api.hetzner.cloud/v1/'; $url = 'https://api.hetzner.cloud/v1/';
$data = []; $data = [];
@@ -125,8 +176,8 @@ function ArkHostHetznerVPS_API(array $params) {
$method = 'GET'; $method = 'GET';
break; break;
case 'Datacenters': case 'Locations':
$url .= 'datacenters'; $url .= 'locations?per_page=50';
$method = 'GET'; $method = 'GET';
break; break;
@@ -160,10 +211,11 @@ function ArkHostHetznerVPS_API(array $params) {
) )
); );
// Add datacenter if specified // Hetzner removed the datacenter request property on 1 July 2026.
$datacenter = ArkHostHetznerVPS_GetOption($params, 'datacenter'); // Normalize legacy values such as fsn1-dc14 before sending location.
if ($datacenter) { $location = ArkHostHetznerVPS_GetLocationOption($params);
$data['datacenter'] = $datacenter; if ($location) {
$data['location'] = $location;
} }
// Handle backups // Handle backups
@@ -975,9 +1027,11 @@ function ArkHostHetznerVPS_ConfigOptions() {
'Type' => 'dropdown', 'Type' => 'dropdown',
'Options' => array(), 'Options' => array(),
), ),
// Keep the original array key and position for existing WHMCS product
// settings. Only the Hetzner-facing value and admin label have changed.
'datacenter' => array( 'datacenter' => array(
'FriendlyName' => 'Datacenter', 'FriendlyName' => 'Location',
'Description' => 'The datacenter location for the server.', 'Description' => 'The Hetzner location for the server (Configurable option: Location or legacy datacenter).',
'Type' => 'dropdown', 'Type' => 'dropdown',
'Options' => array(), 'Options' => array(),
), ),
@@ -993,7 +1047,7 @@ function ArkHostHetznerVPS_ConfigOptions() {
), ),
'floating_ip_location' => array( 'floating_ip_location' => array(
'FriendlyName' => 'Floating IP Location', 'FriendlyName' => 'Floating IP Location',
'Description' => 'Location for floating IPs (same as datacenter)', 'Description' => 'Location for floating IPs (normally the same as the server location).',
'Type' => 'dropdown', 'Type' => 'dropdown',
'Options' => array(), 'Options' => array(),
), ),
@@ -1082,19 +1136,31 @@ function ArkHostHetznerVPS_ConfigOptions() {
} }
} }
// Fetch datacenters // Fetch locations. Hetzner's datacenter endpoints are deprecated
$params['action'] = 'Datacenters'; // and are scheduled for removal after 1 October 2026.
$datacenters = ArkHostHetznerVPS_API($params); $params['action'] = 'Locations';
$locations = ArkHostHetznerVPS_API($params);
if (isset($datacenters['datacenters'])) { if (isset($locations['locations'])) {
foreach ($datacenters['datacenters'] as $datacenter) { foreach ($locations['locations'] as $location) {
$array['datacenter']['Options'] += array( if (empty($location['name'])) {
$datacenter['name'] => $datacenter['description'] . ' (' . $datacenter['location']['city'] . ')' continue;
); }
// Also populate floating IP locations
$array['floating_ip_location']['Options'] += array( $place = array_filter(array(
$datacenter['location']['name'] => $datacenter['location']['city'] . ', ' . $datacenter['location']['country'] $location['city'] ?? '',
); $location['country'] ?? ''
));
$description = !empty($location['description'])
? $location['description']
: $location['name'];
$label = $description;
if (!empty($place)) {
$label .= ' (' . implode(', ', $place) . ')';
}
$array['datacenter']['Options'][$location['name']] = $label;
$array['floating_ip_location']['Options'][$location['name']] = $label;
} }
} }
} }
@@ -1218,7 +1284,9 @@ function ArkHostHetznerVPS_CreateAccount(array $params) {
$floatingIpParams = $params; $floatingIpParams = $params;
$floatingIpParams['action'] = 'Create Floating IP'; $floatingIpParams['action'] = 'Create Floating IP';
$floatingIpParams['ip_type'] = $ipType; $floatingIpParams['ip_type'] = $ipType;
$floatingIpParams['location'] = ArkHostHetznerVPS_GetOption($params, 'floating_ip_location'); $floatingIpParams['location'] = ArkHostHetznerVPS_NormalizeLocation(
ArkHostHetznerVPS_GetOption($params, 'floating_ip_location')
);
$floatingIpParams['description'] = 'Server ID: ' . $create['server']['id']; $floatingIpParams['description'] = 'Server ID: ' . $create['server']['id'];
$floatingIpParams['assign_to_server'] = true; $floatingIpParams['assign_to_server'] = true;
@@ -1691,8 +1759,9 @@ function ArkHostHetznerVPS_ClientAreaAPI(array $params) {
$createParams = $params; $createParams = $params;
$createParams['action'] = 'Create Floating IP'; $createParams['action'] = 'Create Floating IP';
$createParams['ip_type'] = 'ipv4'; $createParams['ip_type'] = 'ipv4';
$createParams['location'] = ArkHostHetznerVPS_GetOption($params, 'floating_ip_location') ?: $createParams['location'] = ArkHostHetznerVPS_NormalizeLocation(
ArkHostHetznerVPS_GetOption($params, 'datacenter'); ArkHostHetznerVPS_GetOption($params, 'floating_ip_location')
) ?: ArkHostHetznerVPS_GetLocationOption($params);
$createParams['description'] = 'WHMCS Service ID: ' . $params['serviceid']; $createParams['description'] = 'WHMCS Service ID: ' . $params['serviceid'];
$createParams['assign_to_server'] = true; $createParams['assign_to_server'] = true;
@@ -2485,21 +2554,31 @@ function ArkHostHetznerVPS_ClientArea(array $params) {
$serverInfo['bandwidth'] = 20480; // 20TB in GB (20 * 1024) $serverInfo['bandwidth'] = 20480; // 20TB in GB (20 * 1024)
$serverInfo['bandwidth_used'] = 0; // Not available via API $serverInfo['bandwidth_used'] = 0; // Not available via API
// Add datacenter info - format as "City, Country" // Hetzner now returns location directly on the server. Retain a fallback
$city = isset($serverInfo['datacenter']['location']['city']) ? $serverInfo['datacenter']['location']['city'] : ''; // for cached/older responses that still contain datacenter.location.
$country = isset($serverInfo['datacenter']['location']['country']) ? $serverInfo['datacenter']['location']['country'] : ''; $locationInfo = array();
if (isset($serverInfo['location']) && is_array($serverInfo['location'])) {
if ($city && $country) { $locationInfo = $serverInfo['location'];
$serverInfo['datacenter'] = $city . ', ' . $country; } elseif (isset($serverInfo['datacenter']['location']) && is_array($serverInfo['datacenter']['location'])) {
} elseif ($city) { $locationInfo = $serverInfo['datacenter']['location'];
$serverInfo['datacenter'] = $city;
} elseif ($country) {
$serverInfo['datacenter'] = $country;
} else {
$serverInfo['datacenter'] = 'N/A';
} }
$serverInfo['location'] = $city ?: 'N/A'; $city = $locationInfo['city'] ?? '';
$country = $locationInfo['country'] ?? '';
if ($city && $country) {
$locationDisplay = $city . ', ' . $country;
} elseif ($city) {
$locationDisplay = $city;
} elseif ($country) {
$locationDisplay = $country;
} else {
$locationDisplay = 'N/A';
}
$serverInfo['location_display'] = $locationDisplay;
// Preserve the former display key for third-party/custom templates.
$serverInfo['datacenter'] = $locationDisplay;
// Get root password with expiration check (72 hours) // Get root password with expiration check (72 hours)
$passwordSetTime = $params['model']->serviceProperties->get('ArkHostHetznerVPS|Password Set Time'); $passwordSetTime = $params['model']->serviceProperties->get('ArkHostHetznerVPS|Password Set Time');
+1 -2
View File
@@ -3,7 +3,7 @@
* WHMCS Server Module - Hetzner VPS Hooks * WHMCS Server Module - Hetzner VPS Hooks
* *
* @package WHMCS * @package WHMCS
* @version 1.2.4 * @version 1.2.5
* @copyright Copyright (c) ArkHost 2025 * @copyright Copyright (c) ArkHost 2025
* @author ArkHost <support@arkhost.com> * @author ArkHost <support@arkhost.com>
* @link https://arkhost.com * @link https://arkhost.com
@@ -70,4 +70,3 @@ add_hook('ClientAreaHeadOutput', 1, function($vars) {
</style> </style>
HTML; HTML;
}); });
@@ -207,7 +207,7 @@
</tr> </tr>
<tr> <tr>
<td class="text-muted">{$ADDONLANG.Overview.Location}:</td> <td class="text-muted">{$ADDONLANG.Overview.Location}:</td>
<td><i class="fa fa-map-marker-alt mr-1"></i>{$serverInfo['datacenter']}</td> <td><i class="fa fa-map-marker-alt mr-1"></i>{$serverInfo['location_display']}</td>
</tr> </tr>
<tr> <tr>
<td class="text-muted">{$ADDONLANG.Overview.ServerType}:</td> <td class="text-muted">{$ADDONLANG.Overview.ServerType}:</td>