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('
')
+ .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' ),
+ )
+ );
+
?>
+
+
+
+
+
Enter your Rent Fetch Sync API key to enable synchronization features.
+
+
+
+