-
-
Notifications
You must be signed in to change notification settings - Fork 66
Add integration for bunnynet #281
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
WalkthroughIntroduces BunnyNet_Host_Provider, a new integration class for BunnyNet CDN/DNS services within WP_Ultimo. Implements domain and subdomain lifecycle hooks for DNS record management, BunnyNet API communication, connection testing, and installation configuration. Includes setup instructions view file. Changes
Sequence DiagramsequenceDiagram
actor Admin
participant WP_Ultimo
participant BunnyNet_Provider
participant BunnyNet_API
participant DNS_System
Admin->>WP_Ultimo: Add new subdomain
WP_Ultimo->>BunnyNet_Provider: on_add_subdomain(subdomain, site_id)
BunnyNet_Provider->>BunnyNet_Provider: Construct domain & API payload
BunnyNet_Provider->>BunnyNet_API: bunnynet_api_call(endpoint, 'POST', dns_data)
BunnyNet_API->>DNS_System: Create DNS records
BunnyNet_API-->>BunnyNet_Provider: Confirm records created
BunnyNet_Provider->>WP_Ultimo: Log success
WP_Ultimo-->>Admin: Subdomain configured
rect rgb(240, 248, 255)
note right of BunnyNet_Provider: Handles www subdomain<br/>automatically if configured
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🧹 Nitpick comments (1)
inc/integrations/host-providers/class-bunnynet-host-provider.php (1)
160-175: Consider adding explicit return for clarity.While
wp_send_json_error()terminates execution internally, adding an explicitreturnafter line 166 would improve code readability and make the control flow clearer.if (! $zone_id) { wp_send_json_error(new \WP_Error('bunnynet-error', __('Zone ID is required.', 'ultimate-multisite'))); + return; }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
assets/img/hosts/bunnynet.svgis excluded by!**/*.svg
📒 Files selected for processing (2)
inc/integrations/host-providers/class-bunnynet-host-provider.php(1 hunks)views/wizards/host-integrations/bunnynet-instructions.php(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
inc/integrations/host-providers/class-bunnynet-host-provider.php (2)
inc/integrations/host-providers/class-base-host-provider.php (1)
supports(337-340)inc/managers/class-domain-manager.php (1)
should_create_www_subdomain(461-484)
🪛 PHPMD (2.15.0)
inc/integrations/host-providers/class-bunnynet-host-provider.php
196-196: Avoid unused parameters such as '$domain'. (undefined)
(UnusedFormalParameter)
196-196: Avoid unused parameters such as '$site_id'. (undefined)
(UnusedFormalParameter)
206-206: Avoid unused parameters such as '$domain'. (undefined)
(UnusedFormalParameter)
206-206: Avoid unused parameters such as '$site_id'. (undefined)
(UnusedFormalParameter)
293-293: Avoid unused parameters such as '$site_id'. (undefined)
(UnusedFormalParameter)
307-307: Avoid unused local variables such as '$original_subdomain'. (undefined)
(UnusedLocalVariable)
🔇 Additional comments (6)
views/wizards/host-integrations/bunnynet-instructions.php (1)
1-102: LGTM!The instructions view is well-structured with proper WordPress i18n escaping using
esc_html_e(). The five-step guide covers the essential BunnyNet setup workflow including security guidance for the API key.inc/integrations/host-providers/class-bunnynet-host-provider.php (5)
21-68: LGTM!Class declaration follows the established pattern from
Base_Host_Provider. The$supportsarray and$constantsdefinitions are correctly configured for BunnyNet integration.
79-119: LGTM!The DNS entries augmentation logic correctly handles the BunnyNet API response, filters records by domain, and properly translates the
@symbol for root domain records.
121-152: LGTM!The
detect()stub andget_fields()implementation are appropriate. The field order shows Zone ID first but the$constantsarray has API Key first - this is fine as field order is for UI while constants are for validation.
196-206: Empty stubs are intentional.The unused parameters flagged by static analysis are expected here - these are interface methods from
Base_Host_Providerthat must maintain the signature even when the implementation doesn't use them.
437-453: LGTM!The
get_explainer_lines()method correctly differentiates between subdomain and subdirectory installs, providing appropriate messaging for each context.
| foreach ($domains_to_send as $subdomain) { | ||
| $server_addr = isset($_SERVER['SERVER_ADDR']) ? sanitize_text_field(wp_unslash($_SERVER['SERVER_ADDR'])) : ''; | ||
|
|
||
| $data = apply_filters( | ||
| 'wu_bunnynet_on_add_domain_data', | ||
| [ | ||
| 'Type' => 0, // A record type | ||
| 'Ttl' => 3600, | ||
| 'Name' => $subdomain, | ||
| 'Value' => $server_addr, | ||
| ], | ||
| $subdomain, | ||
| $site_id | ||
| ); | ||
|
|
||
| $results = $this->bunnynet_api_call("dnszone/$zone_id/records", 'PUT', $data); | ||
|
|
||
| if (is_wp_error($results)) { | ||
| wu_log_add('integration-bunnynet', sprintf('Failed to add subdomain "%s" to BunnyNet. Reason: %s', $subdomain, $results->get_error_message()), LogLevel::ERROR); | ||
|
|
||
| return; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Variable shadowing and potential empty IP address.
Two concerns in this loop:
-
Variable shadowing: Reusing
$subdomainin the foreach (line 256) shadows the outer variable, reducing readability. -
Empty IP address:
$_SERVER['SERVER_ADDR']may be empty in CLI contexts, load balancer setups, or CGI environments. This would create DNS records pointing to an empty value.
- foreach ($domains_to_send as $subdomain) {
+ foreach ($domains_to_send as $subdomain_to_add) {
$server_addr = isset($_SERVER['SERVER_ADDR']) ? sanitize_text_field(wp_unslash($_SERVER['SERVER_ADDR'])) : '';
+ if (empty($server_addr)) {
+ wu_log_add('integration-bunnynet', 'SERVER_ADDR is not available. Cannot determine server IP for DNS record.', LogLevel::ERROR);
+ return;
+ }
+
$data = apply_filters(
'wu_bunnynet_on_add_domain_data',
[
'Type' => 0, // A record type
'Ttl' => 3600,
- 'Name' => $subdomain,
+ 'Name' => $subdomain_to_add,
'Value' => $server_addr,
],
- $subdomain,
+ $subdomain_to_add,
$site_id
);
$results = $this->bunnynet_api_call("dnszone/$zone_id/records", 'PUT', $data);
if (is_wp_error($results)) {
- wu_log_add('integration-bunnynet', sprintf('Failed to add subdomain "%s" to BunnyNet. Reason: %s', $subdomain, $results->get_error_message()), LogLevel::ERROR);
+ wu_log_add('integration-bunnynet', sprintf('Failed to add subdomain "%s" to BunnyNet. Reason: %s', $subdomain_to_add, $results->get_error_message()), LogLevel::ERROR);
return;
}
- wu_log_add('integration-bunnynet', sprintf('Added sub-domain "%s" to BunnyNet.', $subdomain));
+ wu_log_add('integration-bunnynet', sprintf('Added sub-domain "%s" to BunnyNet.', $subdomain_to_add));
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| foreach ($domains_to_send as $subdomain) { | |
| $server_addr = isset($_SERVER['SERVER_ADDR']) ? sanitize_text_field(wp_unslash($_SERVER['SERVER_ADDR'])) : ''; | |
| $data = apply_filters( | |
| 'wu_bunnynet_on_add_domain_data', | |
| [ | |
| 'Type' => 0, // A record type | |
| 'Ttl' => 3600, | |
| 'Name' => $subdomain, | |
| 'Value' => $server_addr, | |
| ], | |
| $subdomain, | |
| $site_id | |
| ); | |
| $results = $this->bunnynet_api_call("dnszone/$zone_id/records", 'PUT', $data); | |
| if (is_wp_error($results)) { | |
| wu_log_add('integration-bunnynet', sprintf('Failed to add subdomain "%s" to BunnyNet. Reason: %s', $subdomain, $results->get_error_message()), LogLevel::ERROR); | |
| return; | |
| } | |
| foreach ($domains_to_send as $subdomain_to_add) { | |
| $server_addr = isset($_SERVER['SERVER_ADDR']) ? sanitize_text_field(wp_unslash($_SERVER['SERVER_ADDR'])) : ''; | |
| if (empty($server_addr)) { | |
| wu_log_add('integration-bunnynet', 'SERVER_ADDR is not available. Cannot determine server IP for DNS record.', LogLevel::ERROR); | |
| return; | |
| } | |
| $data = apply_filters( | |
| 'wu_bunnynet_on_add_domain_data', | |
| [ | |
| 'Type' => 0, // A record type | |
| 'Ttl' => 3600, | |
| 'Name' => $subdomain_to_add, | |
| 'Value' => $server_addr, | |
| ], | |
| $subdomain_to_add, | |
| $site_id | |
| ); | |
| $results = $this->bunnynet_api_call("dnszone/$zone_id/records", 'PUT', $data); | |
| if (is_wp_error($results)) { | |
| wu_log_add('integration-bunnynet', sprintf('Failed to add subdomain "%s" to BunnyNet. Reason: %s', $subdomain_to_add, $results->get_error_message()), LogLevel::ERROR); | |
| return; | |
| } |
🤖 Prompt for AI Agents
inc/integrations/host-providers/class-bunnynet-host-provider.php around lines
256-277: the foreach reuses $subdomain (shadowing an outer variable) and reads
$_SERVER['SERVER_ADDR'] which can be empty; rename the loop variable (e.g.
$domain_to_send) to avoid shadowing, move retrieval and sanitization of the
server IP out of the loop so it's computed once, and if the sanitized
SERVER_ADDR is empty attempt fallbacks such as resolving $_SERVER['SERVER_NAME']
or gethostname() with gethostbyname(), and if still empty log an error and skip
adding that DNS record instead of creating a record with an empty value. Ensure
you update variable names used in the data payload and leave the API call and
error handling logic unchanged otherwise.
| $original_subdomain = $subdomain; | ||
|
|
||
| $subdomain = rtrim(str_replace($current_site->domain, '', $subdomain), '.'); | ||
|
|
||
| if (! $subdomain) { | ||
| return; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
Remove unused variable.
$original_subdomain is assigned but never used. This appears to be leftover from development.
- $original_subdomain = $subdomain;
-
$subdomain = rtrim(str_replace($current_site->domain, '', $subdomain), '.');📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| $original_subdomain = $subdomain; | |
| $subdomain = rtrim(str_replace($current_site->domain, '', $subdomain), '.'); | |
| if (! $subdomain) { | |
| return; | |
| } | |
| $subdomain = rtrim(str_replace($current_site->domain, '', $subdomain), '.'); | |
| if (! $subdomain) { | |
| return; | |
| } |
🧰 Tools
🪛 PHPMD (2.15.0)
307-307: Avoid unused local variables such as '$original_subdomain'. (undefined)
(UnusedLocalVariable)
🤖 Prompt for AI Agents
In inc/integrations/host-providers/class-bunnynet-host-provider.php around lines
307 to 313, the variable $original_subdomain is assigned but never used; remove
the unused assignment to clean up the code by deleting the line that sets
$original_subdomain = $subdomain so only the remaining logic (normalizing
$subdomain and early return) remains.
| protected function bunnynet_api_call($endpoint = 'dnszone', $method = 'GET', $data = []): object { | ||
|
|
||
| $api_url = 'https://api.bunny.net/'; | ||
|
|
||
| $endpoint_url = $api_url . $endpoint; | ||
|
|
||
| $args = [ | ||
| 'method' => $method, | ||
| 'headers' => [ | ||
| 'AccessKey' => defined('WU_BUNNYNET_API_KEY') ? WU_BUNNYNET_API_KEY : '', | ||
| 'Content-Type' => 'application/json', | ||
| ], | ||
| ]; | ||
|
|
||
| if ('GET' !== $method && ! empty($data)) { | ||
| $args['body'] = wp_json_encode($data); | ||
| } | ||
|
|
||
| $response = wp_remote_request($endpoint_url, $args); | ||
|
|
||
| if (! is_wp_error($response)) { | ||
| $body = wp_remote_retrieve_body($response); | ||
| $code = wp_remote_retrieve_response_code($response); | ||
|
|
||
| if ($code >= 200 && $code < 300) { | ||
| return json_decode($body); | ||
| } else { | ||
| $error_message = wp_remote_retrieve_response_message($response); | ||
|
|
||
| $response = new \WP_Error('bunnynet-error', sprintf('%s: %s', $error_message, $body)); | ||
| } | ||
| } | ||
|
|
||
| return $response; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Return type mismatch: method returns \WP_Error but declares object.
The return type declaration object is incorrect since the method can return \WP_Error. Additionally, json_decode() on an empty body returns null, which would violate the object return type.
- protected function bunnynet_api_call($endpoint = 'dnszone', $method = 'GET', $data = []): object {
+ protected function bunnynet_api_call($endpoint = 'dnszone', $method = 'GET', $data = []) {Alternatively, update to a union type if PHP 8.0+ is required:
protected function bunnynet_api_call($endpoint = 'dnszone', $method = 'GET', $data = []): object|\WP_Error {Also consider handling empty responses:
if ($code >= 200 && $code < 300) {
- return json_decode($body);
+ $decoded = json_decode($body);
+ return $decoded ?? (object) [];
} else {🤖 Prompt for AI Agents
In inc/integrations/host-providers/class-bunnynet-host-provider.php around lines
362 to 396, the method declares a return type of object but may return a
\WP_Error or null from json_decode; change the method signature to a union that
allows \WP_Error and null (or remove the return type if running on PHP <8.0),
and add handling for empty or unparseable bodies: after json_decode, if the body
is empty return an empty object (e.g. (object)[]), and if json_decode returns
null while the body is non-empty return a \WP_Error with the json error; ensure
all return paths match the updated signature.
Summary by CodeRabbit
Release Notes
✏️ Tip: You can customize this high-level summary in your review settings.