Add Site Metadata Endpoint and API Key Management

- Introduced a new Site Metadata endpoint (`GET /wp-json/igny8/v1/site-metadata/`) for retrieving available post types and taxonomies, including counts.
- Added API key input in the admin settings for authentication, with secure storage and revocation functionality.
- Implemented a toggle for enabling/disabling two-way sync operations.
- Updated documentation to reflect new features and usage examples.
- Enhanced permission checks for REST API calls to ensure secure access.
This commit is contained in:
IGNY8 VPS (Salman)
2025-11-21 15:18:48 +00:00
parent 1eba4a4e15
commit c35b3c3641
10 changed files with 475 additions and 34 deletions

View File

@@ -64,6 +64,11 @@ class Igny8Admin {
public function register_settings() {
register_setting('igny8_settings', 'igny8_email');
register_setting('igny8_settings', 'igny8_site_id');
register_setting('igny8_settings', 'igny8_enable_two_way_sync', array(
'type' => 'boolean',
'sanitize_callback' => array($this, 'sanitize_boolean'),
'default' => 1
));
register_setting('igny8_bridge_connection', 'igny8_connection_enabled', array(
'type' => 'boolean',
@@ -161,6 +166,17 @@ class Igny8Admin {
$this->handle_connection();
}
// Handle revoke API key
if (isset($_POST['igny8_revoke_api_key']) && check_admin_referer('igny8_revoke_api_key')) {
self::revoke_api_key();
add_settings_error(
'igny8_settings',
'igny8_api_key_revoked',
__('API key revoked and removed from this site.', 'igny8-bridge'),
'updated'
);
}
// Handle webhook secret regeneration
if (isset($_POST['igny8_regenerate_secret']) && check_admin_referer('igny8_regenerate_secret')) {
$new_secret = igny8_regenerate_webhook_secret();
@@ -182,43 +198,78 @@ class Igny8Admin {
private function handle_connection() {
$email = sanitize_email($_POST['igny8_email'] ?? '');
$password = $_POST['igny8_password'] ?? '';
if (empty($email) || empty($password)) {
$api_key = sanitize_text_field($_POST['igny8_api_key'] ?? '');
// Require email, password AND API key per updated policy
if (empty($email) || empty($password) || empty($api_key)) {
add_settings_error(
'igny8_settings',
'igny8_error',
__('Email and password are required.', 'igny8-bridge'),
__('Email, password and API key are all required to establish the connection.', 'igny8-bridge'),
'error'
);
return;
}
// First, attempt login with email/password
$api = new Igny8API();
if ($api->login($email, $password)) {
update_option('igny8_email', $email);
// Try to get site ID (if available)
$site_response = $api->get('/system/sites/');
if ($site_response['success'] && !empty($site_response['results'])) {
$site = $site_response['results'][0];
update_option('igny8_site_id', $site['id']);
}
add_settings_error(
'igny8_settings',
'igny8_connected',
__('Successfully connected to IGNY8 API.', 'igny8-bridge'),
'updated'
);
} else {
if (!$api->login($email, $password)) {
add_settings_error(
'igny8_settings',
'igny8_error',
__('Failed to connect to IGNY8 API. Please check your credentials.', 'igny8-bridge'),
__('Failed to connect to IGNY8 API with provided credentials.', 'igny8-bridge'),
'error'
);
return;
}
// Store email
update_option('igny8_email', $email);
// Store API key securely and also set access token to the API key for subsequent calls if desired
if (function_exists('igny8_store_secure_option')) {
igny8_store_secure_option('igny8_api_key', $api_key);
igny8_store_secure_option('igny8_access_token', $api_key);
} else {
update_option('igny8_api_key', $api_key);
update_option('igny8_access_token', $api_key);
}
// Try to get site ID (if available) using the authenticated client
$site_response = $api->get('/system/sites/');
if ($site_response['success'] && !empty($site_response['results'])) {
$site = $site_response['results'][0];
update_option('igny8_site_id', $site['id']);
}
add_settings_error(
'igny8_settings',
'igny8_connected',
__('Successfully connected to IGNY8 API and stored API key.', 'igny8-bridge'),
'updated'
);
}
/**
* Revoke stored API key (secure delete)
*
* Public so tests can call it directly.
*/
public static function revoke_api_key() {
if (function_exists('igny8_delete_secure_option')) {
igny8_delete_secure_option('igny8_api_key');
igny8_delete_secure_option('igny8_access_token');
igny8_delete_secure_option('igny8_refresh_token');
} else {
delete_option('igny8_api_key');
delete_option('igny8_access_token');
delete_option('igny8_refresh_token');
}
// Also clear token-issued timestamps
delete_option('igny8_token_refreshed_at');
delete_option('igny8_access_token_issued');
}
/**

View File

@@ -15,6 +15,7 @@ $email = get_option('igny8_email', '');
$site_id = get_option('igny8_site_id', '');
$access_token = function_exists('igny8_get_secure_option') ? igny8_get_secure_option('igny8_access_token') : get_option('igny8_access_token');
$is_connected = !empty($access_token);
$api_key = function_exists('igny8_get_secure_option') ? igny8_get_secure_option('igny8_api_key') : get_option('igny8_api_key');
$date_format = get_option('date_format');
$time_format = get_option('time_format');
$now = current_time('timestamp');
@@ -53,6 +54,7 @@ $pending_links = array_filter($link_queue, function($item) {
return $item['status'] === 'pending';
});
$webhook_logs = igny8_get_webhook_logs(array('limit' => 10));
$two_way_sync = (int) get_option('igny8_enable_two_way_sync', 1);
?>
@@ -60,6 +62,13 @@ $webhook_logs = igny8_get_webhook_logs(array('limit' => 10));
<h1><?php echo esc_html(get_admin_page_title()); ?></h1>
<?php settings_errors('igny8_settings'); ?>
<div class="notice notice-info inline" style="margin-top:10px;">
<p>
<strong><?php _e('Integration modes explained:', 'igny8-bridge'); ?></strong><br />
<?php _e('• Enable Sync Operations: controls whether background and manual sync actions occur (cron jobs, webhooks, sync buttons).', 'igny8-bridge'); ?><br />
<?php _e('• Enable Two-Way Sync: controls whether bi-directional syncing (IGNY8 → WordPress and WordPress → IGNY8) is permitted. Disabling this will suppress sync actions but API endpoints remain accessible for discovery and diagnostics.', 'igny8-bridge'); ?>
</p>
</div>
<div class="igny8-settings-container">
<div class="igny8-settings-card">
@@ -87,6 +96,32 @@ $webhook_logs = igny8_get_webhook_logs(array('limit' => 10));
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="igny8_api_key"><?php _e('API Key', 'igny8-bridge'); ?></label>
</th>
<td>
<input
type="password"
id="igny8_api_key"
name="igny8_api_key"
value="<?php echo esc_attr($api_key ? '********' : ''); ?>"
class="regular-text"
placeholder="<?php _e('Paste your IGNY8 API key here (optional)', 'igny8-bridge'); ?>"
/>
<p class="description">
<?php _e('If you have an API key from the IGNY8 SaaS app, paste it here to authenticate the bridge. Leave blank to use email/password.', 'igny8-bridge'); ?>
</p>
<?php if ($api_key) : ?>
<form method="post" action="" style="display:inline-block; margin-left:10px;">
<?php wp_nonce_field('igny8_revoke_api_key'); ?>
<button type="submit" name="igny8_revoke_api_key" class="button button-secondary" onclick="return confirm('<?php _e('Revoke stored API key? This will remove the key from this site.', 'igny8-bridge'); ?>');">
<?php _e('Revoke API Key', 'igny8-bridge'); ?>
</button>
</form>
<?php endif; ?>
</td>
</tr>
<tr>
<th scope="row">
<label for="igny8_password"><?php _e('Password', 'igny8-bridge'); ?></label>
@@ -152,6 +187,23 @@ $webhook_logs = igny8_get_webhook_logs(array('limit' => 10));
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="igny8_enable_two_way_sync"><?php _e('Enable Two-Way Sync', 'igny8-bridge'); ?></label>
</th>
<td>
<label>
<input
type="checkbox"
id="igny8_enable_two_way_sync"
name="igny8_enable_two_way_sync"
value="1"
<?php checked($two_way_sync, 1); ?>
/>
<?php _e('Allow bi-directional sync (IGNY8 ↔ WordPress). When disabled, outbound/inbound sync actions are suppressed but API endpoints remain accessible.', 'igny8-bridge'); ?>
</label>
</td>
</tr>
<?php if ($email) : ?>
<tr>
<th scope="row"><?php _e('Email', 'igny8-bridge'); ?></th>