PluginProbe
Search Atlas SEO – OTTO AI SEO Automation for WordPress / 2.6.15
Search Atlas SEO – OTTO AI SEO Automation for WordPress v2.6.15
2.6.26 2.6.25 2.6.24 2.6.23 2.6.22 2.6.21 2.6.20 2.6.19 2.6.18 2.6.17 2.6.16 2.6.15 2.6.14 2.6.13 2.6.12 2.6.11 2.6.10 2.6.9 2.6.8 2.6.7 2.6.6 2.6.5 2.6.4 2.6.3 2.5.23 All 138 releases
metasync / includes / class-metasync-api-backoff-notices.php

class-metasync-api-backoff-notices.php in Search Atlas SEO – OTTO AI SEO Automation for WordPress 2.6.15, at includes/class-metasync-api-backoff-notices.php

299 lines 9.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * API Backoff Admin Notices
4 *
5 * Handles display of admin notices when API endpoints are in backoff mode.
6 *
7 * @package Metasync
8 * @subpackage Metasync/includes
9 * @since 2.5.15
10 */
11
12 if (!defined('ABSPATH')) {
13 exit;
14 }
15
16 /**
17 * Class Metasync_API_Backoff_Notices
18 *
19 * Displays informative admin notices when API backoff is active.
20 */
21 class Metasync_API_Backoff_Notices {
22
23 /**
24 * Singleton instance
25 *
26 * @var Metasync_API_Backoff_Notices|null
27 */
28 private static $instance = null;
29
30 /**
31 * Backoff manager instance
32 *
33 * @var Metasync_API_Backoff_Manager
34 */
35 private $backoff_manager;
36
37 /**
38 * Private constructor for singleton pattern
39 */
40 private function __construct() {
41 $this->backoff_manager = Metasync_API_Backoff_Manager::get_instance();
42 $this->init_hooks();
43 }
44
45 /**
46 * Get singleton instance
47 *
48 * @return Metasync_API_Backoff_Notices
49 */
50 public static function get_instance() {
51 if (self::$instance === null) {
52 self::$instance = new self();
53 }
54 return self::$instance;
55 }
56
57 /**
58 * Initialize WordPress hooks
59 */
60 private function init_hooks() {
61 // Display admin notices
62 add_action('admin_notices', [$this, 'display_backoff_notices']);
63
64 // Add AJAX handler for dismissing notices
65 add_action('wp_ajax_metasync_dismiss_backoff_notice', [$this, 'ajax_dismiss_notice']);
66
67 // Enqueue admin scripts
68 add_action('admin_enqueue_scripts', [$this, 'enqueue_admin_scripts']);
69 }
70
71 /**
72 * Display backoff notices in admin
73 */
74 public function display_backoff_notices() {
75 // Only show on MetaSync admin pages
76 if (!$this->is_metasync_admin_page()) {
77 return;
78 }
79
80 $active_backoffs = $this->backoff_manager->get_all_active_backoffs();
81
82 if (empty($active_backoffs)) {
83 return;
84 }
85
86 foreach ($active_backoffs as $backoff) {
87 $this->render_backoff_notice($backoff);
88 }
89 }
90
91 /**
92 * Render individual backoff notice
93 *
94 * @param array $backoff Backoff state data.
95 */
96 private function render_backoff_notice(array $backoff) {
97 $endpoint = esc_html($backoff['endpoint']);
98 $time_remaining = Metasync_API_Backoff_Manager::format_time_remaining($backoff['time_remaining']);
99 $occurrence = $backoff['occurrence_count'];
100 $response_code = $backoff['response_code'];
101 $endpoint_hash = $backoff['endpoint_hash'];
102
103 $notice_class = 'notice notice-warning is-dismissible metasync-backoff-notice';
104 $notice_id = 'metasync-backoff-' . esc_attr($endpoint_hash);
105
106 $status_label = $response_code === 429 ? 'Rate Limited' : 'Service Unavailable';
107 $status_icon = '⏸️';
108
109 ?>
110 <div id="<?php echo $notice_id; ?>" class="<?php echo esc_attr($notice_class); ?>" data-endpoint-hash="<?php echo esc_attr($endpoint_hash); ?>">
111 <div style="display: flex; align-items: flex-start; gap: 12px; padding: 4px 0;">
112 <div style="font-size: 24px; line-height: 1;"><?php echo $status_icon; ?></div>
113 <div style="flex: 1;">
114 <p style="margin: 0 0 8px 0; font-weight: 600; font-size: 14px;">
115 <strong>API Backoff Active:</strong> <?php echo esc_html($endpoint); ?>
116 </p>
117 <p style="margin: 0 0 8px 0; font-size: 13px;">
118 <span style="background: #f0f0f1; padding: 3px 8px; border-radius: 3px; margin-right: 8px;">
119 <strong>Status:</strong> <?php echo esc_html($status_label); ?> (<?php echo esc_html($response_code); ?>)
120 </span>
121 <span style="background: #f0f0f1; padding: 3px 8px; border-radius: 3px; margin-right: 8px;">
122 <strong>Occurrence:</strong> <?php echo esc_html($occurrence); ?>/3
123 </span>
124 <span style="background: #fef7f0; color: #b5670e; padding: 3px 8px; border-radius: 3px;">
125 <strong>Time Remaining:</strong> <?php echo esc_html($time_remaining); ?>
126 </span>
127 </p>
128 <p style="margin: 0; font-size: 13px; color: #646970;">
129 All requests to this endpoint are temporarily paused. The plugin will automatically resume requests when the backoff period expires.
130 <?php if ($occurrence < 3): ?>
131 If this continues, the pause duration will increase to prevent further rate limiting.
132 <?php endif; ?>
133 </p>
134 </div>
135 </div>
136 </div>
137 <?php
138 }
139
140 /**
141 * Check if current page is a MetaSync admin page
142 *
143 * @return bool True if on MetaSync admin page.
144 */
145 private function is_metasync_admin_page() {
146 if ( ! function_exists( 'get_current_screen' ) ) {
147 return false;
148 }
149 $screen = get_current_screen();
150
151 if (!$screen) {
152 return false;
153 }
154
155 // Check if on MetaSync settings page or any page with metasync in the ID
156 return strpos($screen->id, 'metasync') !== false ||
157 (isset($_GET['page']) && strpos($_GET['page'], 'metasync') !== false);
158 }
159
160 /**
161 * Enqueue admin scripts for notice handling
162 *
163 * @param string $hook Current admin page hook.
164 */
165 public function enqueue_admin_scripts($hook) {
166 if (!$this->is_metasync_admin_page()) {
167 return;
168 }
169
170 // Enqueue inline script for auto-refresh and dismiss handling
171 wp_add_inline_script('jquery', $this->get_notice_script(), 'after');
172 }
173
174 /**
175 * Get JavaScript for notice handling
176 *
177 * @return string JavaScript code.
178 */
179 private function get_notice_script() {
180 return "
181 jQuery(document).ready(function($) {
182 // Auto-refresh backoff notices every 30 seconds
183 var refreshInterval = setInterval(function() {
184 var backoffNotices = $('.metasync-backoff-notice');
185 if (backoffNotices.length > 0) {
186 // Check if any notices are still active
187 location.reload();
188 } else {
189 // No more notices, stop refreshing
190 clearInterval(refreshInterval);
191 }
192 }, 30000);
193
194 // Handle notice dismissal
195 $(document).on('click', '.metasync-backoff-notice .notice-dismiss', function() {
196 var notice = $(this).closest('.metasync-backoff-notice');
197 var endpointHash = notice.data('endpoint-hash');
198
199 // Optionally send AJAX to log dismissal
200 $.post(ajaxurl, {
201 action: 'metasync_dismiss_backoff_notice',
202 endpoint_hash: endpointHash,
203 nonce: '" . wp_create_nonce('metasync_backoff_notice') . "'
204 });
205 });
206 });
207 ";
208 }
209
210 /**
211 * AJAX handler for dismissing notices
212 */
213 public function ajax_dismiss_notice() {
214 check_ajax_referer('metasync_backoff_notice', 'nonce');
215
216 $endpoint_hash = sanitize_text_field($_POST['endpoint_hash'] ?? '');
217
218 if (empty($endpoint_hash)) {
219 wp_send_json_error(['message' => 'Invalid endpoint hash']);
220 }
221
222 // Log the dismissal (notice will reappear on page refresh if still active)
223 error_log(sprintf(
224 '[MetaSync API_BACKOFF_NOTICE_DISMISSED] User %d dismissed notice for endpoint: %s',
225 get_current_user_id(),
226 $endpoint_hash
227 ));
228
229 wp_send_json_success(['message' => 'Notice dismissed']);
230 }
231
232 /**
233 * Display backoff status in admin bar (optional)
234 *
235 * @param WP_Admin_Bar $wp_admin_bar WordPress admin bar object.
236 */
237 public function add_admin_bar_status($wp_admin_bar) {
238 if (!current_user_can('manage_options')) {
239 return;
240 }
241
242 $active_backoffs = $this->backoff_manager->get_all_active_backoffs();
243
244 if (empty($active_backoffs)) {
245 return;
246 }
247
248 $count = count($active_backoffs);
249
250 $wp_admin_bar->add_node([
251 'id' => 'metasync-backoff-status',
252 'title' => sprintf(
253 '<span style="color: #f0c36d;">⏸️ API Backoff (%d)</span>',
254 $count
255 ),
256 'href' => admin_url('admin.php?page=' . Metasync_Admin::$page_slug),
257 'meta' => [
258 'title' => sprintf(
259 '%d API endpoint%s in backoff mode',
260 $count,
261 $count > 1 ? 's' : ''
262 ),
263 ],
264 ]);
265
266 // Add child nodes for each backoff
267 foreach ($active_backoffs as $backoff) {
268 $wp_admin_bar->add_node([
269 'parent' => 'metasync-backoff-status',
270 'id' => 'metasync-backoff-' . $backoff['endpoint_hash'],
271 'title' => sprintf(
272 '%s - %s remaining',
273 esc_html($backoff['endpoint']),
274 Metasync_API_Backoff_Manager::format_time_remaining($backoff['time_remaining'])
275 ),
276 ]);
277 }
278 }
279
280 /**
281 * Get notice HTML for manual display
282 *
283 * @param string $endpoint_hash Endpoint hash.
284 * @return string Notice HTML.
285 */
286 public function get_notice_html($endpoint_hash) {
287 $backoff = $this->backoff_manager->get_backoff_state($endpoint_hash);
288
289 if (!$backoff || $backoff['time_remaining'] <= 0) {
290 return '';
291 }
292
293 ob_start();
294 $backoff['endpoint_hash'] = $endpoint_hash;
295 $this->render_backoff_notice($backoff);
296 return ob_get_clean();
297 }
298 }
299