Files
igny8/docs/WORDPRESS-PLUGIN-INTEGRATION.md

14 KiB

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

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

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

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

$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

$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

$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

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

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

// 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

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

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

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

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

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