Integrate OpenAPI/Swagger documentation using drf-spectacular, enhancing API documentation with comprehensive guides and schema generation. Add multiple documentation files covering authentication, error codes, rate limiting, and migration strategies. Update settings and URLs to support new documentation endpoints and schema configurations.
This commit is contained in:
575
docs/WORDPRESS-PLUGIN-INTEGRATION.md
Normal file
575
docs/WORDPRESS-PLUGIN-INTEGRATION.md
Normal file
@@ -0,0 +1,575 @@
|
||||
# WordPress Plugin Integration Guide
|
||||
|
||||
**Version**: 1.0.0
|
||||
**Last Updated**: 2025-11-16
|
||||
|
||||
Complete guide for integrating WordPress plugins with IGNY8 API v1.0.
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
This guide helps WordPress plugin developers integrate with the IGNY8 API using the unified response format.
|
||||
|
||||
---
|
||||
|
||||
## Authentication
|
||||
|
||||
### Getting Access Token
|
||||
|
||||
```php
|
||||
function igny8_login($email, $password) {
|
||||
$response = wp_remote_post('https://api.igny8.com/api/v1/auth/login/', [
|
||||
'headers' => [
|
||||
'Content-Type' => 'application/json'
|
||||
],
|
||||
'body' => json_encode([
|
||||
'email' => $email,
|
||||
'password' => $password
|
||||
])
|
||||
]);
|
||||
|
||||
$body = json_decode(wp_remote_retrieve_body($response), true);
|
||||
|
||||
if ($body['success']) {
|
||||
// Store tokens
|
||||
update_option('igny8_access_token', $body['data']['access']);
|
||||
update_option('igny8_refresh_token', $body['data']['refresh']);
|
||||
return $body['data']['access'];
|
||||
} else {
|
||||
return new WP_Error('login_failed', $body['error']);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Using Access Token
|
||||
|
||||
```php
|
||||
function igny8_get_headers() {
|
||||
$token = get_option('igny8_access_token');
|
||||
|
||||
if (!$token) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return [
|
||||
'Authorization' => 'Bearer ' . $token,
|
||||
'Content-Type' => 'application/json'
|
||||
];
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## API Client Class
|
||||
|
||||
### Complete PHP Implementation
|
||||
|
||||
```php
|
||||
class Igny8API {
|
||||
private $base_url = 'https://api.igny8.com/api/v1';
|
||||
private $access_token = null;
|
||||
private $refresh_token = null;
|
||||
|
||||
public function __construct() {
|
||||
$this->access_token = get_option('igny8_access_token');
|
||||
$this->refresh_token = get_option('igny8_refresh_token');
|
||||
}
|
||||
|
||||
/**
|
||||
* Login and store tokens
|
||||
*/
|
||||
public function login($email, $password) {
|
||||
$response = wp_remote_post($this->base_url . '/auth/login/', [
|
||||
'headers' => [
|
||||
'Content-Type' => 'application/json'
|
||||
],
|
||||
'body' => json_encode([
|
||||
'email' => $email,
|
||||
'password' => $password
|
||||
])
|
||||
]);
|
||||
|
||||
$body = $this->parse_response($response);
|
||||
|
||||
if ($body['success']) {
|
||||
$this->access_token = $body['data']['access'];
|
||||
$this->refresh_token = $body['data']['refresh'];
|
||||
|
||||
update_option('igny8_access_token', $this->access_token);
|
||||
update_option('igny8_refresh_token', $this->refresh_token);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh access token
|
||||
*/
|
||||
public function refresh_token() {
|
||||
if (!$this->refresh_token) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$response = wp_remote_post($this->base_url . '/auth/refresh/', [
|
||||
'headers' => [
|
||||
'Content-Type' => 'application/json'
|
||||
],
|
||||
'body' => json_encode([
|
||||
'refresh' => $this->refresh_token
|
||||
])
|
||||
]);
|
||||
|
||||
$body = $this->parse_response($response);
|
||||
|
||||
if ($body['success']) {
|
||||
$this->access_token = $body['data']['access'];
|
||||
$this->refresh_token = $body['data']['refresh'];
|
||||
|
||||
update_option('igny8_access_token', $this->access_token);
|
||||
update_option('igny8_refresh_token', $this->refresh_token);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse unified API response
|
||||
*/
|
||||
private function parse_response($response) {
|
||||
if (is_wp_error($response)) {
|
||||
return [
|
||||
'success' => false,
|
||||
'error' => $response->get_error_message()
|
||||
];
|
||||
}
|
||||
|
||||
$body = json_decode(wp_remote_retrieve_body($response), true);
|
||||
$status_code = wp_remote_retrieve_response_code($response);
|
||||
|
||||
// Handle non-JSON responses
|
||||
if (!$body) {
|
||||
return [
|
||||
'success' => false,
|
||||
'error' => 'Invalid response format'
|
||||
];
|
||||
}
|
||||
|
||||
// Check if response follows unified format
|
||||
if (isset($body['success'])) {
|
||||
return $body;
|
||||
}
|
||||
|
||||
// Legacy format - wrap in unified format
|
||||
if ($status_code >= 200 && $status_code < 300) {
|
||||
return [
|
||||
'success' => true,
|
||||
'data' => $body
|
||||
];
|
||||
} else {
|
||||
return [
|
||||
'success' => false,
|
||||
'error' => $body['detail'] ?? 'Unknown error'
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get headers with authentication
|
||||
*/
|
||||
private function get_headers() {
|
||||
if (!$this->access_token) {
|
||||
throw new Exception('Not authenticated');
|
||||
}
|
||||
|
||||
return [
|
||||
'Authorization' => 'Bearer ' . $this->access_token,
|
||||
'Content-Type' => 'application/json'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Make GET request
|
||||
*/
|
||||
public function get($endpoint) {
|
||||
$response = wp_remote_get($this->base_url . $endpoint, [
|
||||
'headers' => $this->get_headers()
|
||||
]);
|
||||
|
||||
$body = $this->parse_response($response);
|
||||
|
||||
// Handle 401 - token expired
|
||||
if (!$body['success'] && wp_remote_retrieve_response_code($response) == 401) {
|
||||
// Try to refresh token
|
||||
if ($this->refresh_token()) {
|
||||
// Retry request
|
||||
$response = wp_remote_get($this->base_url . $endpoint, [
|
||||
'headers' => $this->get_headers()
|
||||
]);
|
||||
$body = $this->parse_response($response);
|
||||
}
|
||||
}
|
||||
|
||||
return $body;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make POST request
|
||||
*/
|
||||
public function post($endpoint, $data) {
|
||||
$response = wp_remote_post($this->base_url . $endpoint, [
|
||||
'headers' => $this->get_headers(),
|
||||
'body' => json_encode($data)
|
||||
]);
|
||||
|
||||
$body = $this->parse_response($response);
|
||||
|
||||
// Handle 401 - token expired
|
||||
if (!$body['success'] && wp_remote_retrieve_response_code($response) == 401) {
|
||||
// Try to refresh token
|
||||
if ($this->refresh_token()) {
|
||||
// Retry request
|
||||
$response = wp_remote_post($this->base_url . $endpoint, [
|
||||
'headers' => $this->get_headers(),
|
||||
'body' => json_encode($data)
|
||||
]);
|
||||
$body = $this->parse_response($response);
|
||||
}
|
||||
}
|
||||
|
||||
return $body;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make PUT request
|
||||
*/
|
||||
public function put($endpoint, $data) {
|
||||
$response = wp_remote_request($this->base_url . $endpoint, [
|
||||
'method' => 'PUT',
|
||||
'headers' => $this->get_headers(),
|
||||
'body' => json_encode($data)
|
||||
]);
|
||||
|
||||
return $this->parse_response($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make DELETE request
|
||||
*/
|
||||
public function delete($endpoint) {
|
||||
$response = wp_remote_request($this->base_url . $endpoint, [
|
||||
'method' => 'DELETE',
|
||||
'headers' => $this->get_headers()
|
||||
]);
|
||||
|
||||
return $this->parse_response($response);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Get Keywords
|
||||
|
||||
```php
|
||||
$api = new Igny8API();
|
||||
|
||||
// Get keywords
|
||||
$response = $api->get('/planner/keywords/');
|
||||
|
||||
if ($response['success']) {
|
||||
$keywords = $response['results'];
|
||||
$count = $response['count'];
|
||||
|
||||
foreach ($keywords as $keyword) {
|
||||
echo $keyword['name'] . '<br>';
|
||||
}
|
||||
} else {
|
||||
echo 'Error: ' . $response['error'];
|
||||
}
|
||||
```
|
||||
|
||||
### Create Keyword
|
||||
|
||||
```php
|
||||
$api = new Igny8API();
|
||||
|
||||
$data = [
|
||||
'seed_keyword_id' => 1,
|
||||
'site_id' => 1,
|
||||
'sector_id' => 1,
|
||||
'status' => 'active'
|
||||
];
|
||||
|
||||
$response = $api->post('/planner/keywords/', $data);
|
||||
|
||||
if ($response['success']) {
|
||||
$keyword = $response['data'];
|
||||
echo 'Created keyword: ' . $keyword['id'];
|
||||
} else {
|
||||
echo 'Error: ' . $response['error'];
|
||||
if (isset($response['errors'])) {
|
||||
foreach ($response['errors'] as $field => $errors) {
|
||||
echo $field . ': ' . implode(', ', $errors) . '<br>';
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Handle Pagination
|
||||
|
||||
```php
|
||||
$api = new Igny8API();
|
||||
|
||||
function get_all_keywords($api) {
|
||||
$all_keywords = [];
|
||||
$page = 1;
|
||||
|
||||
do {
|
||||
$response = $api->get("/planner/keywords/?page={$page}&page_size=100");
|
||||
|
||||
if ($response['success']) {
|
||||
$all_keywords = array_merge($all_keywords, $response['results']);
|
||||
$page++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} while ($response['next']);
|
||||
|
||||
return $all_keywords;
|
||||
}
|
||||
|
||||
$keywords = get_all_keywords($api);
|
||||
```
|
||||
|
||||
### Handle Rate Limiting
|
||||
|
||||
```php
|
||||
function make_rate_limited_request($api, $endpoint, $max_retries = 3) {
|
||||
for ($attempt = 0; $attempt < $max_retries; $attempt++) {
|
||||
$response = $api->get($endpoint);
|
||||
|
||||
// Check if rate limited
|
||||
if (!$response['success'] && isset($response['error'])) {
|
||||
if (strpos($response['error'], 'Rate limit') !== false) {
|
||||
// Wait before retry
|
||||
sleep(pow(2, $attempt)); // Exponential backoff
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
return ['success' => false, 'error' => 'Max retries exceeded'];
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Unified Error Handling
|
||||
|
||||
```php
|
||||
function handle_api_response($response) {
|
||||
if ($response['success']) {
|
||||
return $response['data'] ?? $response['results'];
|
||||
} else {
|
||||
$error_message = $response['error'];
|
||||
|
||||
// Log error with request ID
|
||||
error_log(sprintf(
|
||||
'IGNY8 API Error: %s (Request ID: %s)',
|
||||
$error_message,
|
||||
$response['request_id'] ?? 'unknown'
|
||||
));
|
||||
|
||||
// Handle field-specific errors
|
||||
if (isset($response['errors'])) {
|
||||
foreach ($response['errors'] as $field => $errors) {
|
||||
error_log(" {$field}: " . implode(', ', $errors));
|
||||
}
|
||||
}
|
||||
|
||||
return new WP_Error('igny8_api_error', $error_message, $response);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Store Tokens Securely
|
||||
|
||||
```php
|
||||
// Use WordPress options API with encryption
|
||||
function save_token($token) {
|
||||
// Encrypt token before storing
|
||||
$encrypted = base64_encode($token);
|
||||
update_option('igny8_access_token', $encrypted, false);
|
||||
}
|
||||
|
||||
function get_token() {
|
||||
$encrypted = get_option('igny8_access_token');
|
||||
return base64_decode($encrypted);
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Implement Token Refresh
|
||||
|
||||
```php
|
||||
function ensure_valid_token($api) {
|
||||
// Check if token is about to expire (refresh 1 minute before)
|
||||
// Token expires in 15 minutes, refresh at 14 minutes
|
||||
$last_refresh = get_option('igny8_token_refreshed_at', 0);
|
||||
|
||||
if (time() - $last_refresh > 14 * 60) {
|
||||
if ($api->refresh_token()) {
|
||||
update_option('igny8_token_refreshed_at', time());
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Cache Responses
|
||||
|
||||
```php
|
||||
function get_cached_keywords($api, $cache_key = 'igny8_keywords', $ttl = 300) {
|
||||
$cached = get_transient($cache_key);
|
||||
|
||||
if ($cached !== false) {
|
||||
return $cached;
|
||||
}
|
||||
|
||||
$response = $api->get('/planner/keywords/');
|
||||
|
||||
if ($response['success']) {
|
||||
$keywords = $response['results'];
|
||||
set_transient($cache_key, $keywords, $ttl);
|
||||
return $keywords;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Handle Rate Limits
|
||||
|
||||
```php
|
||||
function check_rate_limit($response) {
|
||||
// Note: WordPress wp_remote_* doesn't expose all headers easily
|
||||
// Consider using cURL or checking response for 429 status
|
||||
|
||||
if (isset($response['error']) && strpos($response['error'], 'Rate limit') !== false) {
|
||||
// Wait and retry
|
||||
sleep(60);
|
||||
return true; // Should retry
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## WordPress Admin Integration
|
||||
|
||||
### Settings Page
|
||||
|
||||
```php
|
||||
function igny8_settings_page() {
|
||||
?>
|
||||
<div class="wrap">
|
||||
<h1>IGNY8 API Settings</h1>
|
||||
<form method="post" action="options.php">
|
||||
<?php settings_fields('igny8_settings'); ?>
|
||||
<table class="form-table">
|
||||
<tr>
|
||||
<th>API Email</th>
|
||||
<td><input type="email" name="igny8_email" value="<?php echo get_option('igny8_email'); ?>" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>API Password</th>
|
||||
<td><input type="password" name="igny8_password" value="" /></td>
|
||||
</tr>
|
||||
</table>
|
||||
<?php submit_button('Save & Connect'); ?>
|
||||
</form>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
function igny8_save_settings() {
|
||||
if (isset($_POST['igny8_email']) && isset($_POST['igny8_password'])) {
|
||||
$api = new Igny8API();
|
||||
|
||||
if ($api->login($_POST['igny8_email'], $_POST['igny8_password'])) {
|
||||
update_option('igny8_email', $_POST['igny8_email']);
|
||||
add_settings_error('igny8_settings', 'igny8_connected', 'Successfully connected to IGNY8 API', 'updated');
|
||||
} else {
|
||||
add_settings_error('igny8_settings', 'igny8_error', 'Failed to connect to IGNY8 API', 'error');
|
||||
}
|
||||
}
|
||||
}
|
||||
add_action('admin_init', 'igny8_save_settings');
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Testing
|
||||
|
||||
### Unit Tests
|
||||
|
||||
```php
|
||||
class TestIgny8API extends WP_UnitTestCase {
|
||||
public function test_login() {
|
||||
$api = new Igny8API();
|
||||
$result = $api->login('test@example.com', 'password');
|
||||
|
||||
$this->assertTrue($result);
|
||||
$this->assertNotEmpty(get_option('igny8_access_token'));
|
||||
}
|
||||
|
||||
public function test_get_keywords() {
|
||||
$api = new Igny8API();
|
||||
$response = $api->get('/planner/keywords/');
|
||||
|
||||
$this->assertTrue($response['success']);
|
||||
$this->assertArrayHasKey('results', $response);
|
||||
$this->assertArrayHasKey('count', $response);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Issue: Authentication Fails
|
||||
|
||||
**Check**:
|
||||
1. Email and password are correct
|
||||
2. Account is active
|
||||
3. API endpoint is accessible
|
||||
|
||||
### Issue: Token Expires Frequently
|
||||
|
||||
**Solution**: Implement automatic token refresh before expiration.
|
||||
|
||||
### Issue: Rate Limited
|
||||
|
||||
**Solution**: Implement request throttling and caching.
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2025-11-16
|
||||
**API Version**: 1.0.0
|
||||
|
||||
Reference in New Issue
Block a user