API Integration Best Practices for MainWP Add-ons
This guide covers best practices for integrating third-party APIs with MainWP add-ons. Following these practices will help you create reliable, secure, and maintainable integrations.
Real-World MainWP Example: Google Analytics Integration
Here's a concrete example of integrating Google Analytics with MainWP to track website performance across all managed sites:
class MainWP_Google_Analytics_Integration {
private $api_client;
private $view_id;
public function __construct() {
// Initialize Google Analytics API client
$this->api_client = new Google_Analytics_API_Client(
get_option('mainwp_ga_client_id'),
get_option('mainwp_ga_client_secret')
);
// Set default view ID
$this->view_id = get_option('mainwp_ga_view_id');
// Hook into MainWP actions
add_action('mainwp_site_synced', [$this, 'sync_analytics_data'], 10, 2);
add_filter('mainwp_sync_others_data', [$this, 'add_analytics_data_to_sync'], 10, 2);
// Add dashboard widget
add_action('mainwp_dashboard_widgets', [$this, 'add_analytics_widget']);
}
/**
* Sync analytics data when a site is synced
*/
public function sync_analytics_data($website, $data) {
// Skip if API client isn't configured
if (!$this->api_client->is_configured()) {
return;
}
try {
// Get analytics data for this site
$analytics_data = $this->api_client->get_site_analytics(
$website->url,
date('Y-m-d', strtotime('-30 days')),
date('Y-m-d'),
$this->view_id
);
// Store analytics data for this site
update_option('mainwp_ga_data_' . $website->id, $analytics_data);
update_option('mainwp_ga_last_sync_' . $website->id, time());
} catch (Exception $e) {
// Log error but continue
error_log('Google Analytics API Error: ' . $e->getMessage());
}
}
/**
* Add analytics data to sync data
*/
public function add_analytics_data_to_sync($sync_data, $website) {
$sync_data['google_analytics'] = [
'last_sync' => get_option('mainwp_ga_last_sync_' . $website->id, 0),
'has_data' => !empty(get_option('mainwp_ga_data_' . $website->id, []))
];
return $sync_data;
}
/**
* Add analytics widget to dashboard
*/
public function add_analytics_widget() {
wp_add_dashboard_widget(
'mainwp-google-analytics-widget',
'Google Analytics Overview',
[$this, 'render_analytics_widget']
);
}
/**
* Render analytics widget
*/
public function render_analytics_widget() {
// Get all websites
$websites = MainWP\Dashboard\MainWP_DB::instance()->get_websites();
// Collect analytics data
$total_sessions = 0;
$total_users = 0;
$total_pageviews = 0;
foreach ($websites as $website) {
$analytics_data = get_option('mainwp_ga_data_' . $website->id, []);
if (!empty($analytics_data)) {
$total_sessions += $analytics_data['sessions'] ?? 0;
$total_users += $analytics_data['users'] ?? 0;
$total_pageviews += $analytics_data['pageviews'] ?? 0;
}
}
// Display analytics data
?>
<div class="ui grid">
<div class="four wide column">
<div class="ui statistic">
<div class="value"><?php echo number_format($total_sessions); ?></div>
<div class="label">Sessions</div>
</div>
</div>
<div class="four wide column">
<div class="ui statistic">
<div class="value"><?php echo number_format($total_users); ?></div>
<div class="label">Users</div>
</div>
</div>
<div class="four wide column">
<div class="ui statistic">
<div class="value"><?php echo number_format($total_pageviews); ?></div>
<div class="label">Pageviews</div>
</div>
</div>
</div>
<?php
}
}
This example demonstrates:
- Hooking into MainWP events - Using
mainwp_site_syncedto trigger data collection - Extending sync data - Adding custom data to the sync process
- Dashboard integration - Displaying aggregated analytics data in the MainWP dashboard
- Error handling - Gracefully handling API errors without disrupting MainWP
- Data storage - Storing API data per website using WordPress options
Common Pitfalls When Integrating APIs with MainWP
Avoid these common mistakes when building your MainWP API integration:
1. Blocking the Main Thread with Synchronous API Calls
Problem: Making synchronous API calls during critical MainWP operations can cause timeouts and a poor user experience.
Solution: Use asynchronous processing for non-critical operations:
// Instead of this:
function on_site_sync($website_id) {
$this->api_client->sync_data($website_id); // Blocks until complete
}
// Do this:
function on_site_sync($website_id) {
wp_schedule_single_event(
time(),
'my_integration_async_sync',
[$website_id]
);
}
// Then handle it asynchronously:
add_action('my_integration_async_sync', [$this, 'process_async_sync']);
2. Not Respecting API Rate Limits
Problem: MainWP manages multiple sites, and your integration might trigger many API calls at once, quickly hitting rate limits.
Solution: Implement rate limiting and queuing:
// Track API calls with timestamps
private function track_api_call() {
$calls = get_option('my_integration_api_calls', []);
$calls[] = time();
// Keep only the last 100 calls
$calls = array_slice($calls, -100);
update_option('my_integration_api_calls', $calls);
}
// Check if we're within rate limits
private function can_make_api_call() {
$calls = get_option('my_integration_api_calls', []);
$recent_calls = array_filter($calls, function($time) {
return $time > time() - 60; // Last minute
});
return count($recent_calls) < 60; // 60 calls per minute limit
}
3. Storing API Credentials Insecurely
Problem: Storing API keys and secrets in plain text makes them vulnerable to exposure.
Solution: Always encrypt sensitive credentials:
// Encrypt API secret before storing
private function save_api_secret($secret) {
$encrypted = $this->encrypt($secret);
update_option('my_integration_api_secret', $encrypted);
}
// Decrypt when needed
private function get_api_secret() {
$encrypted = get_option('my_integration_api_secret', '');
return $this->decrypt($encrypted);
}
4. Not Handling MainWP Child Site Disconnections
Problem: If a site is removed from MainWP, your integration might continue trying to sync data for it.
Solution: Hook into the site deletion event:
// Clean up when a site is removed from MainWP
add_action('mainwp_site_deleted', function($website_id) {
// Delete site-specific data
delete_option('my_integration_data_' . $website_id);
delete_option('my_integration_last_sync_' . $website_id);
// If needed, notify the third-party service
try {
$this->api_client->remove_site($website_id);
} catch (Exception $e) {
error_log('Failed to remove site from service: ' . $e->getMessage());
}
});
5. Ignoring Error States in the UI
Problem: When API errors occur, users are left in the dark about what went wrong.
Solution: Provide clear error states and recovery options in your UI:
// Store API connection state
public function check_api_connection() {
try {
$result = $this->api_client->test_connection();
update_option('my_integration_connection_status', 'connected');
return true;
} catch (Exception $e) {
update_option('my_integration_connection_status', 'error');
update_option('my_integration_connection_error', $e->getMessage());
return false;
}
}
// Display connection status in admin UI
public function render_connection_status() {
$status = get_option('my_integration_connection_status', '');
if ($status === 'connected') {
echo '<div class="ui green message">Connected to API</div>';
} else if ($status === 'error') {
$error = get_option('my_integration_connection_error', 'Unknown error');
echo '<div class="ui red message">API Connection Error: ' . esc_html($error) . '</div>';
echo '<button class="ui button" id="reconnect-api">Reconnect</button>';
} else {
echo '<div class="ui yellow message">Not connected to API</div>';
}
}
Quick Start for Experienced Developers
// 1. Secure credential storage
class ApiCredentialManager {
public static function save_credentials($api_key, $api_secret) {
// Never store credentials in plain text
update_option('my_integration_api_key', $api_key);
update_option('my_integration_api_secret', self::encrypt($api_secret));
}
private static function encrypt($data) {
if (!defined('AUTH_KEY')) return $data; // Fallback if AUTH_KEY not defined
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-cbc'));
$encrypted = openssl_encrypt($data, 'aes-256-cbc', AUTH_KEY, 0, $iv);
return base64_encode($iv . $encrypted);
}
}
// 2. Implement caching for performance
function get_api_data($endpoint, $params = []) {
$cache_key = 'my_integration_' . md5($endpoint . serialize($params));
$cached = get_transient($cache_key);
if (false !== $cached) {
return $cached; // Return cached data if available
}
// Get fresh data from API
$data = $api_client->get($endpoint, $params);
// Cache for 5 minutes (adjust based on data volatility)
set_transient($cache_key, $data, 5 * MINUTE_IN_SECONDS);
return $data;
}
// 3. Implement graceful error handling
try {
$data = $api_client->get('endpoint');
// Process data
} catch (ApiRateLimitException $e) {
// Log rate limit error and schedule retry
error_log('Rate limit exceeded: ' . $e->getMessage());
wp_schedule_single_event(time() + $e->getRetryAfter(), 'my_integration_retry_api_call', [$endpoint, $params]);
// Show user-friendly message
return ['error' => 'Service temporarily unavailable. Retry scheduled.'];
} catch (ApiException $e) {
// Log error and show user-friendly message
error_log('API Error: ' . $e->getMessage());
return ['error' => 'Unable to connect to service. Please try again later.'];
}
// 4. Implement proper logging
function log_api_activity($action, $status, $message = '') {
$logs = get_option('my_integration_logs', []);
$logs[] = [
'time' => current_time('mysql'),
'action' => $action,
'status' => $status,
'message' => $message
];
// Keep only the last 100 logs
$logs = array_slice($logs, -100);
update_option('my_integration_logs', $logs);
}
Security Considerations
Security should be your top priority when integrating with third-party APIs. Here are key practices to follow:
Secure Storage of API Credentials
Never store API keys, tokens, or secrets in plain text:
/**
* Save API credentials securely
*
* @param string $api_key API key
* @param string $api_secret API secret
* @return bool Whether the credentials were saved
*/
public function save_credentials($api_key, $api_secret) {
// Validate credentials
if (empty($api_key) || empty($api_secret)) {
return false;
}
// Save API key
update_option('my_integration_api_key', $api_key);
// Encrypt and save API secret
$encrypted_secret = $this->encrypt_secret($api_secret);
update_option('my_integration_api_secret', $encrypted_secret);
return true;
}
/**
* Encrypt sensitive data
*
* @param string $data Data to encrypt
* @return string Encrypted data
*/
private function encrypt_secret($data) {
// Use WordPress AUTH_KEY as encryption key
$key = defined('AUTH_KEY') ? AUTH_KEY : 'default-key';
// Generate random initialization vector
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-cbc'));
// Encrypt data
$encrypted = openssl_encrypt($data, 'aes-256-cbc', $key, 0, $iv);
// Combine IV and encrypted data
return base64_encode($iv . $encrypted);
}
/**
* Decrypt sensitive data
*
* @param string $encrypted_data Encrypted data
* @return string Decrypted data
*/
private function decrypt_secret($encrypted_data) {
// Use WordPress AUTH_KEY as encryption key
$key = defined('AUTH_KEY') ? AUTH_KEY : 'default-key';
// Decode combined data
$combined = base64_decode($encrypted_data);
// Extract IV and encrypted data
$iv_length = openssl_cipher_iv_length('aes-256-cbc');
$iv = substr($combined, 0, $iv_length);
$encrypted = substr($combined, $iv_length);
// Decrypt data
return openssl_decrypt($encrypted, 'aes-256-cbc', $key, 0, $iv);
}
Use HTTPS for All API Communication
Always use HTTPS for API communication to prevent man-in-the-middle attacks:
/**
* Ensure API URL uses HTTPS
*
* @param string $url API URL
* @return string Secure API URL
*/
private function ensure_https($url) {
if (strpos($url, 'http://') === 0) {
$url = 'https://' . substr($url, 7);
}
return $url;
}
Implement Proper Authentication
Use the most secure authentication method available:
- OAuth 2.0: Preferred for most APIs
- API Keys with HMAC: Good for server-to-server communication
- JWT: Good for stateless authentication
- Basic Auth: Only use with HTTPS and when no better option is available
Validate and Sanitize All Input
Always validate and sanitize input before sending it to the API:
/**
* Validate API parameters
*
* @param array $params API parameters
* @param array $allowed_params Allowed parameters and their types
* @return array Validated parameters
*/
private function validate_params($params, $allowed_params) {
$validated = [];
foreach ($params as $key => $value) {
// Check if parameter is allowed
if (!isset($allowed_params[$key])) {
continue;
}
// Validate parameter type
$type = $allowed_params[$key];
switch ($type) {
case 'string':
$validated[$key] = sanitize_text_field($value);
break;
case 'int':
$validated[$key] = (int)$value;
break;
case 'float':
$validated[$key] = (float)$value;
break;
case 'bool':
$validated[$key] = (bool)$value;
break;
case 'array':
$validated[$key] = is_array($value) ? $value : [];
break;
default:
$validated[$key] = $value;
break;
}
}
return $validated;
}
Implement Rate Limit Protection
Protect your integration from abuse with rate limiting:
/**
* Check if rate limit is exceeded
*
* @param string $action Action name
* @param int $limit Rate limit
* @param int $period Period in seconds
* @return bool Whether rate limit is exceeded
*/
public function is_rate_limited($action, $limit = 10, $period = 60) {
// Get current user ID
$user_id = get_current_user_id();
if (!$user_id) {
return false;
}
// Get rate limit data
$rate_limits = get_user_meta($user_id, 'my_integration_rate_limits', true);
if (!is_array($rate_limits)) {
$rate_limits = [];
}
// Get action data
$action_data = $rate_limits[$action] ?? [
'count' => 0,
'reset' => time() + $period
];
// Check if period has expired
if (time() > $action_data['reset']) {
// Reset count and period
$action_data = [
'count' => 1,
'reset' => time() + $period
];
// Save rate limit data
$rate_limits[$action] = $action_data;
update_user_meta($user_id, 'my_integration_rate_limits', $rate_limits);
return false;
}
// Check if limit is exceeded
if ($action_data['count'] >= $limit) {
return true;
}
// Increment count
$action_data['count']++;
// Save rate limit data
$rate_limits[$action] = $action_data;
update_user_meta($user_id, 'my_integration_rate_limits', $rate_limits);
return false;
}
Secure Webhook Handling
If your integration uses webhooks, implement proper security:
/**
* Verify webhook signature
*
* @param string $payload Webhook payload
* @param string $signature Webhook signature
* @return bool Whether the signature is valid
*/
public function verify_webhook_signature($payload, $signature) {
// Get webhook secret
$secret = get_option('my_integration_webhook_secret', '');
if (empty($secret)) {
return false;
}
// Calculate expected signature
$expected_signature = hash_hmac('sha256', $payload, $secret);
// Compare signatures
return hash_equals($expected_signature, $signature);
}
Performance Optimization
Optimize your integration for performance to provide a better user experience:
Implement Caching
Cache API responses to reduce API calls and improve performance:
/**
* Get data with caching
*
* @param string $endpoint API endpoint
* @param array $params Query parameters
* @param int $cache_time Cache time in seconds
* @return array Response data
*/
public function get_cached($endpoint, $params = [], $cache_time = 300) {
$cache_key = 'my_integration_' . md5($endpoint . serialize($params));
// Check cache
$cached = get_transient($cache_key);
if (false !== $cached) {
return $cached;
}
// Get fresh data
$data = $this->api_client->get($endpoint, $params);
// Cache the data
set_transient($cache_key, $data, $cache_time);
return $data;
}
Implement Batch Processing
Combine multiple API calls into a single batch request when possible:
/**
* Process batch of API requests
*
* @param array $requests Array of request data
* @return array Response data
*/
public function batch_process($requests) {
// Check if API supports batch processing
if (!$this->api_client->supports_batch()) {
// Process requests individually
$responses = [];
foreach ($requests as $key => $request) {
$responses[$key] = $this->api_client->request(
$request['method'],
$request['endpoint'],
$request['params'] ?? [],
$request['data'] ?? null
);
}
return $responses;
}
// Process requests in a batch
return $this->api_client->batch($requests);
}
Implement Asynchronous Processing
Use WordPress cron for asynchronous processing of non-critical tasks:
/**
* Schedule asynchronous API call
*
* @param string $method HTTP method
* @param string $endpoint API endpoint
* @param array $params Query parameters
* @param array $data Request data
*/
public function schedule_api_call($method, $endpoint, $params = [], $data = null) {
wp_schedule_single_event(
time(),
'my_integration_api_call',
[$method, $endpoint, $params, $data]
);
}
/**
* Process scheduled API call
*
* @param string $method HTTP method
* @param string $endpoint API endpoint
* @param array $params Query parameters
* @param array $data Request data
*/
public function process_scheduled_api_call($method, $endpoint, $params = [], $data = null) {
try {
$response = $this->api_client->request($method, $endpoint, $params, $data);
$this->log_api_activity($endpoint, 'success');
} catch (Exception $e) {
$this->log_api_activity($endpoint, 'error', $e->getMessage());
}
}
Optimize Data Transfer
Minimize the amount of data transferred:
- Request only the data you need: Use API parameters to filter results
- Compress data: Use gzip compression when available
- Use pagination: Request data in smaller chunks
- Use conditional requests: Use ETag or If-Modified-Since headers
/**
* Get paginated data
*
* @param string $endpoint API endpoint
* @param array $params Query parameters
* @param int $page_size Page size
* @return array All data
*/
public function get_all_paginated_data($endpoint, $params = [], $page_size = 100) {
$all_data = [];
$page = 1;
do {
// Get page of data
$page_params = array_merge($params, [
'page' => $page,
'per_page' => $page_size
]);
$data = $this->api_client->get($endpoint, $page_params);
// Add data to result
if (!empty($data)) {
$all_data = array_merge($all_data, $data);
}
// Increment page
$page++;
// Continue until no more data
} while (!empty($data) && count($data) === $page_size);
return $all_data;
}
Error Handling and Graceful Degradation
Implement robust error handling to provide a better user experience:
Implement Comprehensive Error Handling
Handle different types of errors appropriately:
try {
$data = $this->api_client->get('endpoint');
// Process data
} catch (ApiAuthException $e) {
// Handle authentication errors
$this->log_error('Authentication error: ' . $e->getMessage());
$this->notify_admin('API authentication failed. Please check your credentials.');
return $this->get_fallback_data();
} catch (ApiRateLimitException $e) {
// Handle rate limiting
$this->log_error('Rate limit exceeded: ' . $e->getMessage());
$this->schedule_retry($e->getRetryAfter());
return $this->get_cached_data() ?: $this->get_fallback_data();
} catch (ApiServerException $e) {
// Handle server errors
$this->log_error('Server error: ' . $e->getMessage());
return $this->get_cached_data() ?: $this->get_fallback_data();
} catch (ApiClientException $e) {
// Handle client errors
$this->log_error('Client error: ' . $e->getMessage());
return $this->get_fallback_data();
} catch (Exception $e) {
// Handle unexpected errors
$this->log_error('Unexpected error: ' . $e->getMessage());
return $this->get_fallback_data();
}
Implement Retry Logic
Retry failed API calls with exponential backoff:
/**
* Retry API call with exponential backoff
*
* @param string $method HTTP method
* @param string $endpoint API endpoint
* @param array $params Query parameters
* @param array $data Request data
* @param int $retry_count Retry count
* @param int $max_retries Maximum number of retries
* @return array Response data
*/
public function retry_api_call($method, $endpoint, $params = [], $data = null, $retry_count = 0, $max_retries = 3) {
try {
return $this->api_client->request($method, $endpoint, $params, $data);
} catch (ApiRateLimitException $e) {
// Handle rate limiting
$retry_after = $e->getRetryAfter();
if ($retry_count < $max_retries) {
sleep($retry_after);
return $this->retry_api_call($method, $endpoint, $params, $data, $retry_count + 1, $max_retries);
}
throw $e;
} catch (ApiServerException $e) {
// Handle server errors
if ($retry_count < $max_retries) {
$backoff = pow(2, $retry_count);
sleep($backoff);
return $this->retry_api_call($method, $endpoint, $params, $data, $retry_count + 1, $max_retries);
}
throw $e;
} catch (ApiConnectionException $e) {
// Handle connection errors
if ($retry_count < $max_retries) {
$backoff = pow(2, $retry_count);
sleep($backoff);
return $this->retry_api_call($method, $endpoint, $params, $data, $retry_count + 1, $max_retries);
}
throw $e;
}
}
Implement Fallback Mechanisms
Provide fallback mechanisms for when the API is unavailable:
/**
* Get fallback data
*
* @param string $endpoint API endpoint
* @return array Fallback data
*/
public function get_fallback_data($endpoint = '') {
// Check for cached data
$cached = $this->get_cached_data($endpoint);
if ($cached) {
return $cached;
}
// Return default data
switch ($endpoint) {
case 'users':
return ['status' => 'offline', 'data' => []];
case 'stats':
return ['status' => 'offline', 'data' => ['visits' => 0, 'conversions' => 0]];
default:
return ['status' => 'offline', 'data' => []];
}
}
Implement Circuit Breaker Pattern
Implement the circuit breaker pattern to prevent cascading failures:
class CircuitBreaker {
private $failures = 0;
private $threshold = 5;
private $reset_timeout = 60;
private $last_failure_time = 0;
private $state = 'closed'; // closed, open, half-open
/**
* Execute function with circuit breaker
*
* @param callable $func Function to execute
* @return mixed Function result
*/
public function execute($func) {
// Check if circuit is open
if ($this->is_open()) {
// Check if reset timeout has passed
if (time() - $this->last_failure_time > $this->reset_timeout) {
// Set circuit to half-open
$this->state = 'half-open';
} else {
throw new Exception('Circuit is open');
}
}
try {
// Execute function
$result = $func();
// Reset failures on success
if ($this->state === 'half-open') {
$this->reset();
}
return $result;
} catch (Exception $e) {
// Increment failures
$this->failures++;
$this->last_failure_time = time();
// Open circuit if threshold is reached
if ($this->failures >= $this->threshold) {
$this->state = 'open';
}
throw $e;
}
}
/**
* Check if circuit is open
*
* @return bool Whether circuit is open
*/
public function is_open() {
return $this->state === 'open';
}
/**
* Reset circuit
*/
public function reset() {
$this->failures = 0;
$this->state = 'closed';
}
}
User Experience Design for API-Dependent Features
Design your integration with the user experience in mind:
Provide Clear Feedback
Keep users informed about the status of API operations:
/**
* Display API status
*/
public function display_api_status() {
// Check API status
$status = $this->get_api_status();
// Display status
switch ($status) {
case 'connected':
?>
<div class="ui green message">
<i class="check icon"></i>
<?php esc_html_e('Connected to API', 'my-integration'); ?>
</div>
<?php
break;
case 'limited':
?>
<div class="ui yellow message">
<i class="exclamation triangle icon"></i>
<?php esc_html_e('Connected to API with limited functionality', 'my-integration'); ?>
</div>
<?php
break;
case 'disconnected':
?>
<div class="ui red message">
<i class="times icon"></i>
<?php esc_html_e('Disconnected from API', 'my-integration'); ?>
</div>
<?php
break;
}
}
Implement Loading States
Show loading states during API operations:
/**
* Display loading state
*
* @param string $message Loading message
*/
public function display_loading_state($message = '') {
?>
<div class="ui segment loading-state">
<div class="ui active dimmer">
<div class="ui text loader"><?php echo esc_html($message ?: __('Loading...', 'my-integration')); ?></div>
</div>
<p></p>
</div>
<script type="text/javascript">
jQuery(document).ready(function($) {
// Show loading state
$('.loading-state').show();
// Make API request
$.ajax({
url: ajaxurl,
type: 'POST',
data: {
action: 'my_integration_api_request',
nonce: '<?php echo wp_create_nonce('my_integration_api_request'); ?>'
},
success: function(response) {
// Hide loading state
$('.loading-state').hide();
// Display response
if (response.success) {
// Display success message
} else {
// Display error message
}
},
error: function() {
// Hide loading state
$('.loading-state').hide();
// Display error message
}
});
});
</script>
<?php
}
Implement Offline Mode
Allow users to continue working when the API is unavailable:
/**
* Check if offline mode is enabled
*
* @return bool Whether offline mode is enabled
*/
public function is_offline_mode() {
return get_option('my_integration_offline_mode', false);
}
/**
* Enable offline mode
*/
public function enable_offline_mode() {
update_option('my_integration_offline_mode', true);
}
/**
* Disable offline mode
*/
public function disable_offline_mode() {
update_option('my_integration_offline_mode', false);
}
/**
* Get data with offline mode support
*
* @param string $endpoint API endpoint
* @param array $params Query parameters
* @return array Data
*/
public function get_data_with_offline_support($endpoint, $params = []) {
// Check if offline mode is enabled
if ($this->is_offline_mode()) {
return $this->get_fallback_data($endpoint);
}
try {
// Get data from API
return $this->api_client->get($endpoint, $params);
} catch (Exception $e) {
// Enable offline mode
$this->enable_offline_mode();
// Return fallback data
return $this->get_fallback_data($endpoint);
}
}
Data Synchronization Strategies
Implement effective data synchronization between MainWP and the third-party service:
Implement Pull-Based Sync
Pull data from the third-party service on a schedule:
/**
* Schedule regular syncs
*/
public function schedule_syncs() {
// Schedule daily sync if not already scheduled
if (!wp_next_scheduled('my_integration_daily_sync')) {
wp_schedule_event(time(), 'daily', 'my_integration_daily_sync');
}
// Add action hook for the event
add_action('my_integration_daily_sync', [$this, 'sync_all_websites']);
}
/**
* Sync all websites
*/
public function sync_all_websites() {
// Get all MainWP websites
$websites = MainWP\Dashboard\MainWP_DB::instance()->get_websites();
foreach ($websites as $website) {
// Check if integration is enabled for this website
$enabled = get_option('my_integration_enabled_' . $website->id, false);
if (!$enabled) {
continue;
}
// Sync data
$this->sync_from_service($website->id);
}
}
Implement Push-Based Sync
Push data to the third-party service when it changes:
/**
* Hook into MainWP events to push data
*/
public function register_push_hooks() {
// Hook into site added event
add_action('mainwp_site_added', [$this, 'push_site_added'], 10, 1);
// Hook into site updated event
add_action('mainwp_site_updated', [$this, 'push_site_updated'], 10, 1);
// Hook into site deleted event
add_action('mainwp_site_deleted', [$this, 'push_site_deleted'], 10, 1);
}
/**
* Push site added event
*
* @param int $website_id Website ID
*/
public function push_site_added($website_id) {
// Get website details
$website = MainWP\Dashboard\MainWP_DB::instance()->get_website_by_id($website_id);
if (!$website) {
return;
}
// Push data to third-party service
$this->api_client->post('sites', [
'url' => $website->url,
'name' => $website->name
]);
}
Implement Bidirectional Sync
Synchronize data in both directions:
/**
* Perform bidirectional sync
*
* @param int $website_id Website ID
*/
public function bidirectional_sync($website_id) {
// Get website details
$website = MainWP\Dashboard\MainWP_DB::instance()->get_website_by_id($website_id);
if (!$website) {
return;
}
// Get last sync timestamp
$last_sync = get_option('my_integration_last_sync_' . $website_id, 0);
// Get changes from third-party service
$service_changes = $this->api_client->get('sites/' . urlencode($website->url) . '/changes', [
'since' => $last_sync
]);
// Get local changes
$local_changes = $this->get_local_changes($website_id, $last_sync);
// Resolve conflicts
$resolved_changes = $this->resolve_conflicts($service_changes, $local_changes);
// Apply service changes locally
$this->apply_service_changes($website_id, $resolved_changes['local_updates']);
// Push local changes to service
$this->push_local_changes($website_id, $resolved_changes['service_updates']);
// Update last sync timestamp
update_option('my_integration_last_sync_' . $website_id, time());
}
Implement Conflict Resolution
Resolve conflicts when data changes in both systems:
/**
* Resolve conflicts between local and service changes
*
* @param array $service_changes Changes from third-party service
* @param array $local_changes Local changes
* @return array Resolved changes
*/
public function resolve_conflicts($service_changes, $local_changes) {
$local_updates = [];
$service_updates = [];
// Process service changes
foreach ($service_changes as $key => $service_item) {
if (isset($local_changes[$key])) {
// Conflict: both sides have changes
$local_item = $local_changes[$key];
// Resolve based on timestamp (newer wins)
if ($service_item['updated_at'] > $local_item['updated_at']) {
$local_updates[$key] = $service_item;
} else {
$service_updates[$key] = $local_item;
}
// Remove from local changes to mark as processed
unset($local_changes[$key]);
} else {
// No conflict: only service has changes
$local_updates[$key] = $service_item;
}
}
// Remaining local changes need to be sent to service
foreach ($local_changes as $key => $local_item) {
$service_updates[$key] = $local_item;
}
return [
'local_updates' => $local_updates,
'service_updates' => $service_updates
];
}
Handling API Rate Limits and Quotas
Implement strategies to handle API rate limits and quotas:
Implement Rate Limit Tracking
Track API rate limits to avoid exceeding them:
/**
* Track API rate limits
*
* @param array $response API response
*/
public function track_rate_limits($response) {
// Get rate limit headers
$rate_limit = wp_remote_retrieve_header($response, 'X-RateLimit-Limit');
$rate_limit_remaining = wp_remote_retrieve_header($response, 'X-RateLimit-Remaining');
$rate_limit_reset = wp_remote_retrieve_header($response, 'X-RateLimit-Reset');
// Save rate limit data
update_option('my_integration_rate_limit', [
'limit' => $rate_limit,
'remaining' => $rate_limit_remaining,
'reset' => $rate_limit_reset
]);
}
/**
谢谢你的反馈!