diff --git a/inc/integrations/host-providers/class-base-host-provider.php b/inc/integrations/host-providers/class-base-host-provider.php index 51616542..c730e590 100644 --- a/inc/integrations/host-providers/class-base-host-provider.php +++ b/inc/integrations/host-providers/class-base-host-provider.php @@ -100,17 +100,17 @@ public function init(): void { // avoid text domain loaded at the wrong time. add_action('init', [$this, 'alert_provider_not_setup']); } - } - - /* - * Load the dependencies. - */ - $this->load_dependencies(); + } else { + /* + * Load the dependencies. + */ + $this->load_dependencies(); - /* - * Initialize the hooks. - */ - $this->register_hooks(); + /* + * Initialize the hooks. + */ + $this->register_hooks(); + } } add_filter('wu_domain_manager_get_integrations', [$this, 'self_register']); diff --git a/inc/integrations/host-providers/class-closte-host-provider.php b/inc/integrations/host-providers/class-closte-host-provider.php index 7e3598c9..303f5ca3 100644 --- a/inc/integrations/host-providers/class-closte-host-provider.php +++ b/inc/integrations/host-providers/class-closte-host-provider.php @@ -143,7 +143,7 @@ public function on_add_domain($domain, $site_id): void { if (wu_get_isset($domain_response, 'success', false)) { wu_log_add('integration-closte', sprintf('Domain %s added successfully, requesting SSL certificate', $domain)); $this->request_ssl_certificate($domain); - } elseif (isset($domain_response['error']) && 'Invalid or empty domain: ' . $domain === $domain_response['error'] ) { + } elseif (isset($domain_response['error']) && 'Invalid or empty domain: ' . $domain === $domain_response['error']) { wu_log_add('integration-closte', sprintf('Domain %s rejected by Closte API as invalid. This may be expected for Closte subdomains or internal domains.', $domain)); } else { wu_log_add('integration-closte', sprintf('Failed to add domain %s. Response: %s', $domain, wp_json_encode($domain_response))); @@ -218,8 +218,6 @@ private function request_ssl_certificate($domain) { '/certificate/install', ]; - $ssl_response = null; - foreach ($ssl_endpoints as $endpoint) { wu_log_add('integration-closte', sprintf('Trying SSL endpoint: %s', $endpoint)); @@ -255,7 +253,7 @@ private function request_ssl_certificate($domain) { * * @since 2.0.0 * @param string $domain The domain to check SSL status for. - * @return array|object + * @return array */ public function check_ssl_status($domain) { @@ -302,13 +300,13 @@ public function test_connection(): void { * @since 1.7.3 * @param string $endpoint Endpoint to send the call to. * @param array $data Array containing the params to the call. - * @return object + * @return array */ public function send_closte_api_request($endpoint, $data) { if (defined('CLOSTE_CLIENT_API_KEY') === false) { wu_log_add('integration-closte', 'CLOSTE_CLIENT_API_KEY constant not defined'); - return (object) [ + return [ 'success' => false, 'error' => 'Closte API Key not found.', ]; @@ -316,7 +314,7 @@ public function send_closte_api_request($endpoint, $data) { if (empty(CLOSTE_CLIENT_API_KEY)) { wu_log_add('integration-closte', 'CLOSTE_CLIENT_API_KEY is empty'); - return (object) [ + return [ 'success' => false, 'error' => 'Closte API Key is empty.', ]; @@ -362,7 +360,7 @@ public function send_closte_api_request($endpoint, $data) { // Check for HTTP errors if ($response_code >= 400) { wu_log_add('integration-closte', sprintf('HTTP error %d for endpoint %s', $response_code, $endpoint)); - return (object) [ + return [ 'success' => false, 'error' => sprintf('HTTP %d error', $response_code), 'response_body' => $response_body, @@ -384,7 +382,7 @@ public function send_closte_api_request($endpoint, $data) { } wu_log_add('integration-closte', sprintf('JSON decode error: %s', json_last_error_msg())); - return (object) [ + return [ 'success' => false, 'error' => 'Invalid JSON response', 'json_error' => json_last_error_msg(), @@ -392,7 +390,7 @@ public function send_closte_api_request($endpoint, $data) { } wu_log_add('integration-closte', 'Empty response body'); - return (object) [ + return [ 'success' => false, 'error' => 'Empty response', ]; diff --git a/inc/integrations/host-providers/class-enhance-host-provider.php b/inc/integrations/host-providers/class-enhance-host-provider.php index 06981e09..e8fb7ed2 100644 --- a/inc/integrations/host-providers/class-enhance-host-provider.php +++ b/inc/integrations/host-providers/class-enhance-host-provider.php @@ -65,7 +65,8 @@ class Enhance_Host_Provider extends Base_Host_Provider { protected $constants = [ 'WU_ENHANCE_API_TOKEN', 'WU_ENHANCE_API_URL', - 'WU_ENHANCE_SERVER_ID', + 'WU_ENHANCE_ORG_ID', + 'WU_ENHANCE_WEBSITE_ID', ]; /** @@ -98,18 +99,37 @@ public function detect(): bool { public function get_fields() { return [ - 'WU_ENHANCE_API_TOKEN' => [ + 'WU_ENHANCE_API_TOKEN' => [ 'type' => 'password', + 'html_attr' => ['autocomplete' => 'new-password'], 'title' => __('Enhance API Token', 'ultimate-multisite'), + 'desc' => sprintf( + /* translators: %s is the link to the API token documentation */ + __('Generate an API token in your Enhance Control Panel under Settings → API Tokens. Learn more', 'ultimate-multisite'), + 'https://apidocs.enhance.com/#section/Authentication' + ), 'placeholder' => __('Your bearer token', 'ultimate-multisite'), ], - 'WU_ENHANCE_API_URL' => [ + 'WU_ENHANCE_API_URL' => [ 'title' => __('Enhance API URL', 'ultimate-multisite'), - 'placeholder' => __('e.g. https://your-enhance-server.com', 'ultimate-multisite'), + 'desc' => __('The API URL of your Enhance Control Panel (e.g., https://your-enhance-server.com/api).', 'ultimate-multisite'), + 'placeholder' => __('e.g. https://your-enhance-server.com/api', 'ultimate-multisite'), + 'html_attr' => [ + 'id' => 'wu_enhance_api_url', + ], ], - 'WU_ENHANCE_SERVER_ID' => [ - 'title' => __('Server ID', 'ultimate-multisite'), - 'placeholder' => __('UUID of your server', 'ultimate-multisite'), + 'WU_ENHANCE_ORG_ID' => [ + 'title' => __('Organization ID', 'ultimate-multisite'), + 'desc' => __('The UUID of your organization. You can find this in your Enhance Control Panel URL when viewing the organization (e.g., /org/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx).', 'ultimate-multisite'), + 'placeholder' => __('e.g. xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', 'ultimate-multisite'), + 'html_attr' => [ + 'id' => 'wu_enhance_org_id', + ], + ], + 'WU_ENHANCE_WEBSITE_ID' => [ + 'title' => __('Website ID', 'ultimate-multisite'), + 'placeholder' => __('e.g. xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', 'ultimate-multisite'), + 'desc' => __('The UUID of the website where domains should be added. You can find this in your Enhance Control Panel URL when viewing a website (e.g., /websites/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx).', 'ultimate-multisite'), ], ]; } @@ -126,24 +146,33 @@ public function on_add_domain($domain, $site_id): void { wu_log_add('integration-enhance', sprintf('Adding domain: %s for site ID: %d', $domain, $site_id)); - $server_id = defined('WU_ENHANCE_SERVER_ID') ? WU_ENHANCE_SERVER_ID : ''; + $org_id = defined('WU_ENHANCE_ORG_ID') ? WU_ENHANCE_ORG_ID : ''; + $website_id = defined('WU_ENHANCE_WEBSITE_ID') ? WU_ENHANCE_WEBSITE_ID : ''; + + if (empty($org_id)) { + wu_log_add('integration-enhance', 'Organization ID not configured'); + return; + } - if (empty($server_id)) { - wu_log_add('integration-enhance', 'Server ID not configured'); + if (empty($website_id)) { + wu_log_add('integration-enhance', 'Website ID not configured'); return; } - // Add the domain to the server + // Add the domain to the website + // POST /orgs/{org_id}/websites/{website_id}/domains + $domain_data = [ + 'domain' => $domain, + ]; + $domain_response = $this->send_enhance_api_request( - '/servers/' . $server_id . '/domains', + '/orgs/' . $org_id . '/websites/' . $website_id . '/domains', 'POST', - [ - 'domain' => $domain, - ] + $domain_data ); // Check if domain was added successfully - if (wu_get_isset($domain_response, 'id')) { + if (wu_get_isset($domain_response, 'id') || (isset($domain_response['success']) && $domain_response['success'])) { wu_log_add('integration-enhance', sprintf('Domain %s added successfully. SSL will be automatically provisioned via LetsEncrypt when DNS resolves.', $domain)); } elseif (isset($domain_response['error'])) { wu_log_add('integration-enhance', sprintf('Failed to add domain %s. Error: %s', $domain, wp_json_encode($domain_response))); @@ -164,17 +193,23 @@ public function on_remove_domain($domain, $site_id): void { wu_log_add('integration-enhance', sprintf('Removing domain: %s for site ID: %d', $domain, $site_id)); - $server_id = defined('WU_ENHANCE_SERVER_ID') ? WU_ENHANCE_SERVER_ID : ''; + $org_id = defined('WU_ENHANCE_ORG_ID') ? WU_ENHANCE_ORG_ID : ''; + $website_id = defined('WU_ENHANCE_WEBSITE_ID') ? WU_ENHANCE_WEBSITE_ID : ''; - if (empty($server_id)) { - wu_log_add('integration-enhance', 'Server ID not configured'); + if (empty($org_id)) { + wu_log_add('integration-enhance', 'Organization ID not configured'); + return; + } + + if (empty($website_id)) { + wu_log_add('integration-enhance', 'Website ID not configured'); return; } // First, get the domain ID by listing domains and finding a match + // GET /orgs/{org_id}/websites/{website_id}/domains $domains_list = $this->send_enhance_api_request( - '/servers/' . $server_id . '/domains', - 'GET' + '/orgs/' . $org_id . '/websites/' . $website_id . '/domains' ); $domain_id = null; @@ -194,8 +229,9 @@ public function on_remove_domain($domain, $site_id): void { } // Delete the domain - $delete_response = $this->send_enhance_api_request( - '/servers/' . $server_id . '/domains/' . $domain_id, + // DELETE /orgs/{org_id}/websites/{website_id}/domains/{domain_id} + $this->send_enhance_api_request( + '/orgs/' . $org_id . '/websites/' . $website_id . '/domains/' . $domain_id, 'DELETE' ); @@ -240,28 +276,36 @@ public function on_remove_subdomain($subdomain, $site_id): void { */ public function test_connection(): void { - $server_id = defined('WU_ENHANCE_SERVER_ID') ? WU_ENHANCE_SERVER_ID : ''; + $org_id = defined('WU_ENHANCE_ORG_ID') ? WU_ENHANCE_ORG_ID : ''; + $website_id = defined('WU_ENHANCE_WEBSITE_ID') ? WU_ENHANCE_WEBSITE_ID : ''; + + if (empty($org_id)) { + $error = new \WP_Error('no-org-id', __('Organization ID is not configured', 'ultimate-multisite')); + wp_send_json_error($error); + return; + } - if (empty($server_id)) { - $error = new \WP_Error('no-server-id', __('Server ID is not configured', 'ultimate-multisite')); + if (empty($website_id)) { + $error = new \WP_Error('no-website-id', __('Website ID is not configured', 'ultimate-multisite')); wp_send_json_error($error); return; } - // Test by attempting to list domains + // Test by attempting to get website info. + // GET /orgs/{org_id}/websites/{website_id} $response = $this->send_enhance_api_request( - '/servers/' . $server_id . '/domains', - 'GET' + '/orgs/' . $org_id . '/websites/' . $website_id ); - if (isset($response['items']) || isset($response['id'])) { + if (isset($response['id'])) { wp_send_json_success( [ 'message' => __('Connection successful', 'ultimate-multisite'), ] ); } else { - $error = new \WP_Error('connection-failed', __('Failed to connect to Enhance API', 'ultimate-multisite')); + // Translators: %s the full error message. + $error = new \WP_Error('connection-failed', sprintf(__('Failed to connect to Enhance API: %s', 'ultimate-multisite'), $response['error'] ?? 'Unknown error')); wp_send_json_error($error); } } @@ -270,9 +314,9 @@ public function test_connection(): void { * Sends a request to the Enhance API with the configured bearer token. * * @since 2.0.0 - * @param string $endpoint API endpoint (relative to base URL). - * @param string $method HTTP method (GET, POST, DELETE, etc.). - * @param array $data Request body data (for POST/PUT/PATCH). + * @param string $endpoint API endpoint (relative to base URL). + * @param string $method HTTP method (GET, POST, DELETE, etc.). + * @param array|string $data Request body data (for POST/PUT/PATCH). * @return array|object */ public function send_enhance_api_request($endpoint, $method = 'GET', $data = []) { diff --git a/inc/integrations/host-providers/class-gridpane-host-provider.php b/inc/integrations/host-providers/class-gridpane-host-provider.php index 8cb375dc..599dea6e 100644 --- a/inc/integrations/host-providers/class-gridpane-host-provider.php +++ b/inc/integrations/host-providers/class-gridpane-host-provider.php @@ -62,6 +62,9 @@ class Gridpane_Host_Provider extends Base_Host_Provider { */ protected $constants = [ 'WU_GRIDPANE', + 'WU_GRIDPANE_API_KEY', + 'WU_GRIDPANE_APP_ID', + 'WU_GRIDPANE_SERVER_ID', ]; /** diff --git a/inc/integrations/host-providers/class-wpengine-host-provider.php b/inc/integrations/host-providers/class-wpengine-host-provider.php index 4416ebc7..599765ec 100644 --- a/inc/integrations/host-providers/class-wpengine-host-provider.php +++ b/inc/integrations/host-providers/class-wpengine-host-provider.php @@ -105,7 +105,9 @@ public function load_dependencies(): void { * @return void */ public function on_add_domain($domain, $site_id): void { - + if (! class_exists('WPE_API')) { + return; + } $api = new \WPE_API(); $api->set_arg('method', 'domain'); @@ -124,6 +126,9 @@ public function on_add_domain($domain, $site_id): void { * @return void */ public function on_remove_domain($domain, $site_id): void { + if (! class_exists('WPE_API')) { + return; + } $api = new \WPE_API(); @@ -197,6 +202,9 @@ public function get_logo() { * @return void */ public function test_connection(): void { + if (! class_exists('WPE_API')) { + wp_send_json_error(__('Class WPE_API is not installed.', 'ultimate-multisite')); + } $api = new \WPE_API();