From 8659e5a898212a61569f1e042462e0468b242a34 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Feb 2026 10:25:39 +0000 Subject: [PATCH 1/5] Initial plan From a316346a7d51d93b4248c6f8aa0fff9c9ead8b90 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Feb 2026 10:28:51 +0000 Subject: [PATCH 2/5] Add RFS API key setting with validation Co-authored-by: jonschr <2929672+jonschr@users.noreply.github.com> --- assets/js/rentfetch-rfs-api-key-validation.js | 100 +++++++++++++ lib/admin/ajax-validate-rfs-api-key.php | 137 ++++++++++++++++++ lib/admin/sync-options.php | 27 ++++ lib/initialization/enqueue.php | 8 + 4 files changed, 272 insertions(+) create mode 100644 assets/js/rentfetch-rfs-api-key-validation.js create mode 100644 lib/admin/ajax-validate-rfs-api-key.php diff --git a/assets/js/rentfetch-rfs-api-key-validation.js b/assets/js/rentfetch-rfs-api-key-validation.js new file mode 100644 index 0000000..8d502a0 --- /dev/null +++ b/assets/js/rentfetch-rfs-api-key-validation.js @@ -0,0 +1,100 @@ +jQuery(document).ready(function ($) { + var $apiKeyInput = $('#rentfetch_options_rfs_api_key'); + var $validateButton = $('#rfs_validate_api_key'); + var $statusDiv = $('#rfs_api_key_status'); + + /** + * Display a status message + * + * @param {string} message The message to display + * @param {string} type The type of message: 'success', 'error', 'warning', or 'info' + */ + function displayStatus(message, type) { + var cssClass = 'notice notice-' + type; + $statusDiv + .html('

' + message + '

') + .show(); + } + + /** + * Validate the API key + * + * @param {boolean} showLoadingState Whether to show a loading state on the button + */ + function validateApiKey(showLoadingState) { + var apiKey = $apiKeyInput.val().trim(); + + if (!apiKey) { + displayStatus('Please enter an API key.', 'warning'); + return; + } + + if (showLoadingState) { + $validateButton.prop('disabled', true).text('Validating...'); + } + + var ajaxUrl = + typeof rfs_ajax_object !== 'undefined' + ? rfs_ajax_object.ajax_url + : '/wp-admin/admin-ajax.php'; + + $.post(ajaxUrl, { + action: 'rfs_validate_api_key', + api_key: apiKey, + _ajax_nonce: + typeof rfs_ajax_object !== 'undefined' + ? rfs_ajax_object.nonce + : '', + }) + .done(function (response) { + if (response.success) { + var data = response.data; + var status = data.status; + var message = data.message; + + switch (status) { + case 'valid': + displayStatus(message, 'success'); + break; + case 'not_found': + displayStatus(message, 'error'); + break; + case 'in_use': + displayStatus(message, 'warning'); + break; + default: + displayStatus(message, 'info'); + break; + } + } else { + displayStatus( + 'Error validating API key: ' + + (response.data || 'Unknown error'), + 'error' + ); + } + }) + .fail(function (xhr, status, error) { + displayStatus( + 'Network error while validating API key: ' + error, + 'error' + ); + }) + .always(function () { + if (showLoadingState) { + $validateButton.prop('disabled', false).text('Validate Key'); + } + }); + } + + // Validate on button click + $validateButton.on('click', function (e) { + e.preventDefault(); + validateApiKey(true); + }); + + // Validate on page load if API key exists + if ($apiKeyInput.length && $apiKeyInput.val().trim()) { + validateApiKey(false); + } +}); diff --git a/lib/admin/ajax-validate-rfs-api-key.php b/lib/admin/ajax-validate-rfs-api-key.php new file mode 100644 index 0000000..fdfe0d3 --- /dev/null +++ b/lib/admin/ajax-validate-rfs-api-key.php @@ -0,0 +1,137 @@ +get_error_message() ); + } + + wp_send_json_success( $validation_result ); +} +add_action( 'wp_ajax_rfs_validate_api_key', 'rfs_validate_api_key_ajax_handler' ); + +/** + * Validate the API key with the Rent Fetch API + * + * @param string $api_key The API key to validate. + * + * @return array|WP_Error The validation result or WP_Error on failure. + */ +function rfs_validate_api_key_with_api( $api_key ) { + + // Get the site URL for validation + $site_url = get_site_url(); + + // Clean up the site URL to just the domain name + $site_url = preg_replace( '#^(https?://)?(www\.)?([^/]+).*$#', '$3', $site_url ); + + // Prepare the request body + $body = array( + 'api_key' => $api_key, + 'site_url' => $site_url, + ); + + // Get the API URL (allow override via constant for testing) + $api_url = defined( 'RENTFETCH_API_VALIDATE_URL' ) + ? constant( 'RENTFETCH_API_VALIDATE_URL' ) + : 'https://api.rentfetch.net/wp-json/rentfetchapi/v1/validate-key'; + + // Make the API request + $response = wp_remote_post( + $api_url, + array( + 'method' => 'POST', + 'body' => wp_json_encode( $body ), + 'headers' => array( + 'Content-Type' => 'application/json', + ), + 'timeout' => 15, + ) + ); + + // Check for errors + if ( is_wp_error( $response ) ) { + return new WP_Error( + 'api_request_failed', + 'Unable to connect to Rent Fetch API: ' . $response->get_error_message() + ); + } + + $response_code = wp_remote_retrieve_response_code( $response ); + $response_body = wp_remote_retrieve_body( $response ); + + // Parse the response + $data = json_decode( $response_body, true ); + + // Handle different response codes + switch ( $response_code ) { + case 200: + // Valid API key + return array( + 'status' => 'valid', + 'message' => isset( $data['message'] ) + ? $data['message'] + : 'API key is valid and ready to use.', + ); + + case 404: + // API key not found + return array( + 'status' => 'not_found', + 'message' => isset( $data['message'] ) + ? $data['message'] + : 'API key not found. Please check your key and try again.', + ); + + case 409: + // API key already in use on another site + $existing_site = isset( $data['existing_site'] ) ? $data['existing_site'] : 'another site'; + return array( + 'status' => 'in_use', + 'message' => isset( $data['message'] ) + ? $data['message'] + : sprintf( 'This API key is already in use on %s.', $existing_site ), + ); + + default: + // Unexpected response + return new WP_Error( + 'unexpected_response', + sprintf( + 'Unexpected response from API (HTTP %d): %s', + $response_code, + isset( $data['message'] ) ? $data['message'] : wp_remote_retrieve_response_message( $response ) + ) + ); + } +} diff --git a/lib/admin/sync-options.php b/lib/admin/sync-options.php index 413e9bc..f48663e 100644 --- a/lib/admin/sync-options.php +++ b/lib/admin/sync-options.php @@ -13,6 +13,20 @@ function rentfetch_remove_premium_functionality_notice() { */ add_action( 'rentfetch_do_settings_general_data_sync', 'rentfetch_settings_sync', 25 ); function rentfetch_settings_sync() { + + // Enqueue the API key validation script + wp_enqueue_script( 'rentfetch-rfs-api-key-validation' ); + + // Localize script to pass AJAX URL and nonce + wp_localize_script( + 'rentfetch-rfs-api-key-validation', + 'rfs_ajax_object', + array( + 'ajax_url' => admin_url( 'admin-ajax.php' ), + 'nonce' => wp_create_nonce( 'rfs_ajax_nonce' ), + ) + ); + ?>

Data Sync

@@ -46,6 +60,19 @@ function rentfetch_settings_sync() {
+ +
+
+ +

Enter your Rent Fetch Sync API key to enable synchronization features.

+
+ + +
+
+
+
+