576 lines
14 KiB
Markdown
576 lines
14 KiB
Markdown
# 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
|
|
|