PluginProbe
Search Atlas SEO – OTTO AI SEO Automation for WordPress / 2.7.1
Search Atlas SEO – OTTO AI SEO Automation for WordPress v2.7.1
2.7.1 2.7.2 2.7.0 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 All 141 releases
← All changes | includes/class-metasync-site-health.php +345 -153 2.6.13 → 2.7.1 View file →
@@ -136,52 +136,79 @@
136 136 $rate_limit_log = get_option( 'metasync_otto_rate_limit_log', [] );
137 137 $last_backoff_time = ! empty( $rate_limit_log ) ? max( $rate_limit_log ) : null;
138 138 $last_backoff_value = $last_backoff_time
139 139 ? wp_date( 'Y-m-d H:i:s', $last_backoff_time ) . ' (' . human_time_diff( $last_backoff_time ) . ' ago)'
140 - : __( 'Never' );
140 + : __( 'Never', 'metasync' );
141 141
142 + $otto_job_counts = class_exists( 'Metasync_Otto_Job_Status' ) ? Metasync_Otto_Job_Status::counts() : [];
143 + $otto_job_fields = [];
144 + if ( ! empty( $otto_job_counts ) ) {
145 + $otto_job_fields = [
146 + 'otto_jobs_accepted' => [
147 + 'label' => __( 'Crawl Jobs - Accepted', 'metasync' ),
148 + 'value' => (int) $otto_job_counts['accepted'],
149 + ],
150 + 'otto_jobs_retrying' => [
151 + 'label' => __( 'Crawl Jobs - Retrying', 'metasync' ),
152 + 'value' => (int) $otto_job_counts['retrying'],
153 + ],
154 + 'otto_jobs_completed' => [
155 + 'label' => __( 'Crawl Jobs - Completed', 'metasync' ),
156 + 'value' => (int) $otto_job_counts['completed'],
157 + ],
158 + 'otto_jobs_failed' => [
159 + 'label' => __( 'Crawl Jobs - Failed', 'metasync' ),
160 + 'value' => (int) $otto_job_counts['failed'],
161 + ],
162 + 'otto_jobs_pending' => [
163 + 'label' => __( 'Crawl Jobs - Queued Overflow', 'metasync' ),
164 + 'value' => (int) $otto_job_counts['pending'],
165 + ],
166 + ];
167 + }
168 +
142 169 $info['metasync'] = [
143 170 'label' => $plugin_name,
144 171 'fields' => [
145 172 'version' => [
146 - 'label' => __( 'Plugin Version' ),
173 + 'label' => __( 'Plugin Version', 'metasync' ),
147 174 'value' => METASYNC_VERSION,
148 175 ],
149 176 'queue_pending' => [
150 - 'label' => __( 'Queue - Pending Jobs' ),
177 + 'label' => __( 'Queue - Pending Jobs', 'metasync' ),
151 178 'value' => isset( $queue_stats['metasync_pending'] ) ? (int) $queue_stats['metasync_pending'] : 0,
152 179 ],
153 180 'queue_completed' => [
154 - 'label' => __( 'Queue - Completed Jobs' ),
181 + 'label' => __( 'Queue - Completed Jobs', 'metasync' ),
155 182 'value' => $completed_count,
156 183 ],
157 184 'queue_failed_24h' => [
158 - 'label' => __( 'Queue - Failed Jobs (last 24h)' ),
185 + 'label' => __( 'Queue - Failed Jobs (last 24h)', 'metasync' ),
159 186 'value' => isset( $failed_stats['count'] ) ? (int) $failed_stats['count'] : 0,
160 187 ],
161 - ] + $performance_fields + [
188 + ] + $performance_fields + $otto_job_fields + [
162 189 'last_api_backoff' => [
163 - 'label' => __( 'Last API Backoff Event' ),
190 + 'label' => __( 'Last API Backoff Event', 'metasync' ),
164 191 'value' => $last_backoff_value,
165 192 ],
166 193 'memory_limit' => [
167 - 'label' => __( 'Memory - PHP Limit' ),
194 + 'label' => __( 'Memory - PHP Limit', 'metasync' ),
168 195 'value' => $memory_stats['limit_formatted'],
169 196 ],
170 197 'memory_current' => [
171 - 'label' => __( 'Memory - Current Usage' ),
198 + 'label' => __( 'Memory - Current Usage', 'metasync' ),
172 199 'value' => $memory_stats['current_formatted'],
173 200 ],
174 201 'memory_peak' => [
175 - 'label' => __( 'Memory - Peak Usage' ),
202 + 'label' => __( 'Memory - Peak Usage', 'metasync' ),
176 203 'value' => $memory_stats['peak_formatted'],
177 204 ],
178 205 'memory_percentage' => [
179 - 'label' => __( 'Memory - Usage Percentage' ),
180 - 'value' => $unlimited ? __( 'N/A (unlimited)' ) : $memory_stats['percentage'] . '%',
206 + 'label' => __( 'Memory - Usage Percentage', 'metasync' ),
207 + 'value' => $unlimited ? __( 'N/A (unlimited)', 'metasync' ) : $memory_stats['percentage'] . '%',
181 208 ],
182 209 'memory_available' => [
183 - 'label' => __( 'Memory - Available' ),
210 + 'label' => __( 'Memory - Available', 'metasync' ),
184 211 'value' => $memory_stats['available_formatted'],
185 212 ],
186 213 ],
187 214 ];
@@ -201,36 +228,45 @@
201 228 {
202 229 add_filter('site_status_tests', function ($tests) {
203 230 // WordPress Cron Queue Health Check
204 231 $tests['direct']['metasync_queue_size'] = [
205 - 'label' => __('WordPress Cron Queue Health'),
232 + 'label' => __('WordPress Cron Queue Health', 'metasync'),
206 233 'test' => [$this, 'queue_size_check']
207 234 ];
208 235
209 236 // Memory Usage Health Check
210 237 $tests['direct']['metasync_memory_usage'] = [
211 - 'label' => __('PHP Memory Usage'),
238 + 'label' => __('PHP Memory Usage', 'metasync'),
212 239 'test' => [$this, 'memory_usage_check']
213 240 ];
214 241
215 242 // OTTO API Rate Limit Health Check
216 243 $tests['direct']['metasync_otto_rate_limit'] = [
217 - 'label' => sprintf(__('%s OTTO API Rate Limit'), Metasync::get_effective_plugin_name()),
244 + /* translators: %s: effective plugin name (whitelabel-aware). */
245 + 'label' => sprintf(__('%s OTTO API Rate Limit', 'metasync'), Metasync::get_effective_plugin_name()),
218 246 'test' => [$this, 'otto_rate_limit_check']
219 247 ];
220 248
221 249 // Debug Mode Health Check
222 250 $tests['direct']['metasync_debug_mode'] = [
223 - 'label' => __('WordPress Debug Mode'),
251 + 'label' => __('WordPress Debug Mode', 'metasync'),
224 252 'test' => [$this, 'debug_mode_check']
225 253 ];
226 254
227 255 // Failed Actions Health Check
228 256 $tests['direct']['metasync_failed_actions'] = [
229 - 'label' => __('MetaSync Failed Actions'),
257 + /* translators: %s: effective plugin name (whitelabel-aware). */
258 + 'label' => sprintf(__('%s Failed Actions', 'metasync'), Metasync::get_effective_plugin_name()),
230 259 'test' => [$this, 'failed_actions_check']
231 260 ];
232 261
262 + // OTTO Crawl Job Reliability Health Check
263 + $tests['direct']['metasync_otto_job_reliability'] = [
264 + /* translators: %s: OTTO name (whitelabel). */
265 + 'label' => sprintf(__('%s Crawl Job Reliability', 'metasync'), Metasync::get_whitelabel_otto_name()),
266 + 'test' => [$this, 'otto_job_reliability_check']
267 + ];
268 +
233 269 return $tests;
234 270 });
235 271 }
236 272
@@ -247,9 +283,9 @@
247 283 private function get_cron_option_size()
248 284 {
249 285 global $wpdb;
250 286
251 - $size = $wpdb->get_var(
287 + $size = $wpdb->get_var( // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- Site Health diagnostic — live on-demand size probe in wp-admin; caching would serve stale sizes
252 288 $wpdb->prepare(
253 289 "SELECT LENGTH(option_value) FROM {$wpdb->options} WHERE option_name = %s",
254 290 'cron'
255 291 )
@@ -361,17 +397,18 @@
361 397
362 398 // Handle excessive size error
363 399 if (isset($stats['error']) && $stats['error'] === 'excessive_size') {
364 400 return [
365 - 'label' => __('WordPress cron queue is excessively large'),
401 + 'label' => __('WordPress cron queue is excessively large', 'metasync'),
366 402 'status' => 'critical',
367 403 'badge' => [
368 - 'label' => __('MetaSync'),
404 + 'label' => Metasync::get_effective_plugin_name(),
369 405 'color' => 'red'
370 406 ],
371 407 'description' => sprintf(
372 - '<p>' . __('The WordPress cron data is excessively large (%s). This can cause severe performance issues including slow page loads, high memory usage, and potential timeouts.') . '</p>' .
373 - '<p>' . __('This typically occurs when cron jobs accumulate from deactivated plugins or failed operations.') . '</p>',
408 + /* translators: %s: formatted size of the cron data. */
409 + '<p>' . __('The WordPress cron data is excessively large (%s). This can cause severe performance issues including slow page loads, high memory usage, and potential timeouts.', 'metasync') . '</p>' .
410 + '<p>' . __('This typically occurs when cron jobs accumulate from deactivated plugins or failed operations.', 'metasync') . '</p>',
374 411 size_format($stats['size'])
375 412 ),
376 413 'actions' => sprintf(
377 414 '<p><strong>%s</strong></p>' .
@@ -379,12 +416,12 @@
379 416 '<li>%s</li>' .
380 417 '<li>%s</li>' .
381 418 '<li>%s</li>' .
382 419 '</ul>',
383 - __('Recommended Actions:'),
384 - __('Use WP-CLI to list and clean up old cron jobs: <code>wp cron event list</code>'),
385 - __('Install a cron management plugin to identify and remove orphaned jobs'),
386 - __('Consider clearing the cron option and letting WordPress rebuild it from active plugins')
420 + __('Recommended Actions:', 'metasync'),
421 + __('Use WP-CLI to list and clean up old cron jobs: <code>wp cron event list</code>', 'metasync'),
422 + __('Install a cron management plugin to identify and remove orphaned jobs', 'metasync'),
423 + __('Consider clearing the cron option and letting WordPress rebuild it from active plugins', 'metasync')
387 424 ),
388 425 'test' => 'metasync_queue_size'
389 426 ];
390 427 }
@@ -397,12 +434,12 @@
397 434 // Determine status based on TOTAL system-wide ONE-TIME jobs from ALL sources
398 435 // This includes WordPress core, all plugins, themes, and custom code
399 436 if ($one_time_count <= self::PENDING_JOBS_THRESHOLD) {
400 437 $status = 'good';
401 - $label = __('WordPress cron queue is healthy');
438 + $label = __('WordPress cron queue is healthy', 'metasync');
402 439 } else {
403 440 $status = 'critical';
404 - $label = __('WordPress cron queue has high pending job count');
441 + $label = __('WordPress cron queue has high pending job count', 'metasync');
405 442 }
406 443
407 444 // Build detailed description showing system-wide statistics
408 445 $description = sprintf(
@@ -411,14 +448,16 @@
411 448 '<li>%s <strong>%s</strong></li>' .
412 449 '<li>%s %d</li>' .
413 450 '<li>%s %d</li>' .
414 451 '</ul>',
415 - __('WordPress Cron Queue Statistics (All Sources):'),
416 - __('Total pending jobs (one-time events):'),
417 - $truncated ? sprintf(__('%d+'), $one_time_count) : number_format($one_time_count),
418 - __('Total scheduled events (recurring):'),
452 + __('WordPress Cron Queue Statistics (All Sources):', 'metasync'),
453 + __('Total pending jobs (one-time events):', 'metasync'),
454 + /* translators: %d: number of pending one-time cron events. */
455 + $truncated ? sprintf(__('%d+', 'metasync'), $one_time_count) : number_format($one_time_count),
456 + __('Total scheduled events (recurring):', 'metasync'),
419 457 $recurring_count,
420 - __('MetaSync pending jobs:'),
458 + /* translators: %s: effective plugin name (whitelabel-aware). */
459 + sprintf(__('%s pending jobs:', 'metasync'), Metasync::get_effective_plugin_name()),
421 460 $metasync_count
422 461 );
423 462
424 463 // Add context about what these numbers mean
@@ -423,13 +462,17 @@
423 462
424 463 // Add context about what these numbers mean
425 464 $description .= sprintf(
426 465 '<p><em>%s</em></p>',
427 - __('Pending jobs are one-time tasks awaiting execution. Recurring events are permanent schedules that run automatically.')
466 + __('Pending jobs are one-time tasks awaiting execution. Recurring events are permanent schedules that run automatically.', 'metasync')
428 467 );
429 468
430 - // If status is not good, provide actionable recommendations
431 - if ($status === 'recommended') {
469 + // If status is not good, provide actionable recommendations. The
470 + // status is only ever 'good' or 'critical' here, so the previous
471 + // '=== recommended' comparison made this entire guidance block dead
472 + // code — exactly when the queue went critical, operators got no
473 + // diagnostics at all.
474 + if ($status !== 'good') {
432 475 $description .= sprintf(
433 476 '<p><strong>%s</strong></p>' .
434 477 '<ul>' .
435 478 '<li>%s</li>' .
@@ -435,12 +478,12 @@
435 478 '<li>%s</li>' .
436 479 '<li>%s</li>' .
437 480 '<li>%s</li>' .
438 481 '</ul>',
439 - __('A high number of pending jobs may indicate:'),
440 - __('WordPress cron is not running properly (check if WP-Cron is disabled or blocked)'),
441 - __('High volume of scheduled tasks from plugins creating jobs faster than they can be processed'),
442 - __('Slow server performance or resource constraints preventing timely job execution')
482 + __('A high number of pending jobs may indicate:', 'metasync'),
483 + __('WordPress cron is not running properly (check if WP-Cron is disabled or blocked)', 'metasync'),
484 + __('High volume of scheduled tasks from plugins creating jobs faster than they can be processed', 'metasync'),
485 + __('Slow server performance or resource constraints preventing timely job execution', 'metasync')
443 486 );
444 487
445 488 // If MetaSync is a significant contributor, add specific guidance
446 489 if ($metasync_count > 500) {
@@ -445,12 +488,16 @@
445 488 // If MetaSync is a significant contributor, add specific guidance
446 489 if ($metasync_count > 500) {
447 490 $description .= sprintf(
448 491 '<p><strong>%s</strong> %s</p>',
449 - __('MetaSync Contribution:'),
492 + /* translators: %s: effective plugin name (whitelabel-aware). */
493 + sprintf(__('%s Contribution:', 'metasync'), Metasync::get_effective_plugin_name()),
450 494 sprintf(
451 - __('MetaSync has %s pending OTTO SEO processing jobs. This may indicate high crawl volume from OTTO or slow processing. Consider reviewing OTTO crawl settings if this number continues to grow.'),
452 - number_format($metasync_count)
495 + /* translators: 1: effective plugin name (whitelabel-aware), 2: formatted job count, 3: OTTO name (whitelabel). */
496 + __('%1$s has %2$s pending %3$s SEO processing jobs. This may indicate high crawl volume from %3$s or slow processing. Consider reviewing %3$s crawl settings if this number continues to grow.', 'metasync'),
497 + Metasync::get_effective_plugin_name(),
498 + number_format($metasync_count),
499 + Metasync::get_whitelabel_otto_name()
453 500 )
454 501 );
455 502 }
456 503
@@ -461,21 +508,21 @@
461 508 '<li>%s</li>' .
462 509 '<li>%s</li>' .
463 510 '<li>%s</li>' .
464 511 '</ul>',
465 - __('Recommended Actions:'),
466 - __('Verify WordPress cron is functioning: Tools → Site Health → Info → WordPress Constants → DISABLE_WP_CRON should be false'),
467 - __('Check server logs for cron execution errors or timeouts'),
468 - __('Consider using a real system cron instead of WP-Cron for better reliability')
512 + __('Recommended Actions:', 'metasync'),
513 + __('Verify WordPress cron is functioning: Tools → Site Health → Info → WordPress Constants → DISABLE_WP_CRON should be false', 'metasync'),
514 + __('Check server logs for cron execution errors or timeouts', 'metasync'),
515 + __('Consider using a real system cron instead of WP-Cron for better reliability', 'metasync')
469 516 );
470 517
471 518 $description .= sprintf(
472 519 '<p>%s %s</p>',
473 - __( 'Quick link:' ),
520 + __( 'Quick link:', 'metasync' ),
474 521 sprintf(
475 522 '<a href="%s">%s</a>',
476 523 esc_url( admin_url( 'site-health.php?tab=debug' ) ),
477 - esc_html( __( 'Site Health Info (check DISABLE_WP_CRON)' ) )
524 + esc_html( __( 'Site Health Info (check DISABLE_WP_CRON)', 'metasync' ) )
478 525 )
479 526 );
480 527 }
481 528
@@ -482,9 +529,9 @@
482 529 return [
483 530 'label' => $label,
484 531 'status' => $status,
485 532 'badge' => [
486 - 'label' => __('MetaSync'),
533 + 'label' => Metasync::get_effective_plugin_name(),
487 534 'color' => $status === 'good' ? 'green' : 'red'
488 535 ],
489 536 'description' => $description,
490 537 'test' => 'metasync_queue_size'
@@ -540,9 +587,9 @@
540 587 if ($memory_limit === '-1') {
541 588 return [
542 589 'limit' => -1,
543 590 'limit_bytes' => -1,
544 - 'limit_formatted' => __('Unlimited'),
591 + 'limit_formatted' => __('Unlimited', 'metasync'),
545 592 'current' => memory_get_usage(true),
546 593 'current_formatted' => size_format(memory_get_usage(true)),
547 594 'peak' => memory_get_peak_usage(true),
548 595 'peak_formatted' => size_format(memory_get_peak_usage(true)),
@@ -547,9 +594,9 @@
547 594 'peak' => memory_get_peak_usage(true),
548 595 'peak_formatted' => size_format(memory_get_peak_usage(true)),
549 596 'percentage' => 0,
550 597 'available' => -1,
551 - 'available_formatted' => __('Unlimited')
598 + 'available_formatted' => __('Unlimited', 'metasync')
552 599 ];
553 600 }
554 601
555 602 // Convert limit to bytes
@@ -598,12 +645,12 @@
598 645
599 646 // Handle unlimited memory
600 647 if ($stats['limit_bytes'] === -1) {
601 648 return [
602 - 'label' => __('PHP memory limit is unlimited'),
649 + 'label' => __('PHP memory limit is unlimited', 'metasync'),
603 650 'status' => 'good',
604 651 'badge' => [
605 - 'label' => __('MetaSync'),
652 + 'label' => Metasync::get_effective_plugin_name(),
606 653 'color' => 'green'
607 654 ],
608 655 'description' => sprintf(
609 656 '<p>%s</p>' .
@@ -611,13 +658,13 @@
611 658 '<ul>' .
612 659 '<li>%s %s</li>' .
613 660 '<li>%s %s</li>' .
614 661 '</ul>',
615 - __('PHP memory limit is set to unlimited. While this prevents memory errors, it may allow poorly optimized code to consume excessive server resources.'),
616 - __('Current Memory Usage:'),
617 - __('Current usage:'),
662 + __('PHP memory limit is set to unlimited. While this prevents memory errors, it may allow poorly optimized code to consume excessive server resources.', 'metasync'),
663 + __('Current Memory Usage:', 'metasync'),
664 + __('Current usage:', 'metasync'),
618 665 $stats['current_formatted'],
619 - __('Peak usage:'),
666 + __('Peak usage:', 'metasync'),
620 667 $stats['peak_formatted']
621 668 ),
622 669 'test' => 'metasync_memory_usage'
623 670 ];
@@ -627,12 +674,12 @@
627 674
628 675 // Determine status based on memory usage percentage
629 676 if ($percentage > self::MEMORY_CRITICAL_THRESHOLD) {
630 677 $status = 'critical';
631 - $label = __('PHP memory usage is critically high');
678 + $label = __('PHP memory usage is critically high', 'metasync');
632 679 } else {
633 680 $status = 'good';
634 - $label = __('PHP memory usage is healthy');
681 + $label = __('PHP memory usage is healthy', 'metasync');
635 682 }
636 683
637 684 // Build detailed description
638 685 $description = sprintf(
@@ -643,19 +690,19 @@
643 690 '<li>%s %s</li>' .
644 691 '<li>%s <strong>%.2f%%</strong></li>' .
645 692 '<li>%s %s</li>' .
646 693 '</ul>',
647 - __('PHP Memory Statistics:'),
648 - __('Memory limit:'),
694 + __('PHP Memory Statistics:', 'metasync'),
695 + __('Memory limit:', 'metasync'),
649 696 $stats['limit_formatted'],
650 697 $stats['limit'],
651 - __('Current usage:'),
698 + __('Current usage:', 'metasync'),
652 699 $stats['current_formatted'],
653 - __('Peak usage:'),
700 + __('Peak usage:', 'metasync'),
654 701 $stats['peak_formatted'],
655 - __('Usage percentage:'),
702 + __('Usage percentage:', 'metasync'),
656 703 $percentage,
657 - __('Available memory:'),
704 + __('Available memory:', 'metasync'),
658 705 $stats['available_formatted']
659 706 );
660 707
661 708 // Add context about memory usage
@@ -661,9 +708,9 @@
661 708 // Add context about memory usage
662 709 if ($status === 'good') {
663 710 $description .= sprintf(
664 711 '<p><em>%s</em></p>',
665 - __('Memory usage is within acceptable limits. The site has sufficient memory available for normal operations.')
712 + __('Memory usage is within acceptable limits. The site has sufficient memory available for normal operations.', 'metasync')
666 713 );
667 714 } else {
668 715 // Critical status - provide actionable recommendations
669 716 $description .= sprintf(
@@ -674,14 +721,14 @@
674 721 '<li>%s</li>' .
675 722 '<li>%s</li>' .
676 723 '<li>%s</li>' .
677 724 '</ul>',
678 - __('Critical Memory Usage Detected:'),
679 - __('PHP memory usage is critically high (>90%). This may cause:'),
680 - __('Fatal errors: "Allowed memory size exhausted"'),
681 - __('Failed page loads and white screens'),
682 - __('Incomplete plugin/theme operations'),
683 - __('Performance degradation and slow response times')
725 + __('Critical Memory Usage Detected:', 'metasync'),
726 + __('PHP memory usage is critically high (>90%). This may cause:', 'metasync'),
727 + __('Fatal errors: "Allowed memory size exhausted"', 'metasync'),
728 + __('Failed page loads and white screens', 'metasync'),
729 + __('Incomplete plugin/theme operations', 'metasync'),
730 + __('Performance degradation and slow response times', 'metasync')
684 731 );
685 732
686 733 $description .= sprintf(
687 734 '<p><strong>%s</strong></p>' .
@@ -691,17 +738,18 @@
691 738 '<li>%s</li>' .
692 739 '<li>%s</li>' .
693 740 '<li>%s</li>' .
694 741 '</ul>',
695 - __('Recommended Actions:'),
742 + __('Recommended Actions:', 'metasync'),
696 743 sprintf(
697 - __('Increase PHP memory limit in wp-config.php: <code>define(\'WP_MEMORY_LIMIT\', \'256M\');</code> (current: %s)'),
744 + /* translators: %s: current PHP memory limit. */
745 + __('Increase PHP memory limit in wp-config.php: <code>define(\'WP_MEMORY_LIMIT\', \'256M\');</code> (current: %s)', 'metasync'),
698 746 $stats['limit']
699 747 ),
700 - __('Contact your hosting provider to increase server memory limits'),
701 - __('Deactivate unnecessary plugins that consume excessive memory'),
702 - __('Optimize images and reduce media library size'),
703 - __('Consider upgrading to a hosting plan with more resources')
748 + __('Contact your hosting provider to increase server memory limits', 'metasync'),
749 + __('Deactivate unnecessary plugins that consume excessive memory', 'metasync'),
750 + __('Optimize images and reduce media library size', 'metasync'),
751 + __('Consider upgrading to a hosting plan with more resources', 'metasync')
704 752 );
705 753
706 754 // Add warning if peak usage is also high
707 755 if ($stats['peak'] > ($stats['limit_bytes'] * 0.95)) {
@@ -706,11 +754,12 @@
706 754 // Add warning if peak usage is also high
707 755 if ($stats['peak'] > ($stats['limit_bytes'] * 0.95)) {
708 756 $description .= sprintf(
709 757 '<p><strong>%s</strong> %s</p>',
710 - __('Warning:'),
758 + __('Warning:', 'metasync'),
711 759 sprintf(
712 - __('Peak memory usage (%s) is very close to the limit. Memory errors may occur during high-traffic periods or resource-intensive operations.'),
760 + /* translators: %s: formatted peak memory usage. */
761 + __('Peak memory usage (%s) is very close to the limit. Memory errors may occur during high-traffic periods or resource-intensive operations.', 'metasync'),
713 762 $stats['peak_formatted']
714 763 )
715 764 );
716 765 }
@@ -716,13 +765,13 @@
716 765 }
717 766
718 767 $description .= sprintf(
719 768 '<p>%s %s</p>',
720 - __( 'Quick link:' ),
769 + __( 'Quick link:', 'metasync' ),
721 770 sprintf(
722 771 '<a href="%s">%s</a>',
723 772 esc_url( admin_url( 'plugins.php' ) ),
724 - esc_html( __( 'Manage Plugins (deactivate memory-heavy plugins)' ) )
773 + esc_html( __( 'Manage Plugins (deactivate memory-heavy plugins)', 'metasync' ) )
725 774 )
726 775 );
727 776 }
728 777
@@ -729,9 +778,9 @@
729 778 return [
730 779 'label' => $label,
731 780 'status' => $status,
732 781 'badge' => [
733 - 'label' => __('MetaSync'),
782 + 'label' => Metasync::get_effective_plugin_name(),
734 783 'color' => $status === 'critical' ? 'red' : 'green'
735 784 ],
736 785 'description' => $description,
737 786 'test' => 'metasync_memory_usage'
@@ -783,17 +832,19 @@
783 832
784 833 // Format the last hit timestamp if available
785 834 $last_hit_text = $last_hit
786 835 ? sprintf(
787 - __('Last occurrence: %s'),
836 + /* translators: %s: date and time of the last occurrence. */
837 + __('Last occurrence: %s', 'metasync'),
788 838 date_i18n(get_option('date_format') . ' ' . get_option('time_format'), $last_hit)
789 839 )
790 - : __('No rate limit hits recorded.');
840 + : __('No rate limit hits recorded.', 'metasync');
791 841
792 842 if ($hits >= self::RATE_LIMIT_CRITICAL_THRESHOLD) {
793 843 $status = 'critical';
794 844 $label = sprintf(
795 - __('%s OTTO API is being rate limited frequently (%d times in 24h)'),
845 + /* translators: 1: effective plugin name (whitelabel-aware), 2: number of rate limit hits. */
846 + __('%1$s OTTO API is being rate limited frequently (%2$d times in 24h)', 'metasync'),
796 847 Metasync::get_effective_plugin_name(),
797 848 $hits
798 849 );
799 850 } elseif ($hits >= self::RATE_LIMIT_WARNING_THRESHOLD) {
@@ -798,15 +849,17 @@
798 849 );
799 850 } elseif ($hits >= self::RATE_LIMIT_WARNING_THRESHOLD) {
800 851 $status = 'recommended';
801 852 $label = sprintf(
802 - __('%s OTTO API rate limit hit %d times in the last 24 hours'),
853 + /* translators: 1: effective plugin name (whitelabel-aware), 2: number of rate limit hits. */
854 + __('%1$s OTTO API rate limit hit %2$d times in the last 24 hours', 'metasync'),
803 855 Metasync::get_effective_plugin_name(),
804 856 $hits
805 857 );
806 858 } else {
807 859 $status = 'good';
808 - $label = sprintf(__('%s OTTO API rate limits are within normal range'), Metasync::get_effective_plugin_name());
860 + /* translators: %s: effective plugin name (whitelabel-aware). */
861 + $label = sprintf(__('%s OTTO API rate limits are within normal range', 'metasync'), Metasync::get_effective_plugin_name());
809 862 }
810 863
811 864 // Build description
812 865 $description = sprintf(
@@ -814,10 +867,11 @@
814 867 '<ul>' .
815 868 '<li>%s <strong>%d</strong></li>' .
816 869 '<li>%s</li>' .
817 870 '</ul>',
818 - __('OTTO API Rate Limit Statistics (last 24 hours):'),
819 - __('HTTP 429 responses received:'),
871 + /* translators: %s: OTTO name (whitelabel). */
872 + sprintf(__('%s API Rate Limit Statistics (last 24 hours):', 'metasync'), Metasync::get_whitelabel_otto_name()),
873 + __('HTTP 429 responses received:', 'metasync'),
820 874 $hits,
821 875 $last_hit_text
822 876 );
823 877
@@ -823,9 +877,10 @@
823 877
824 878 if ($status === 'good') {
825 879 $description .= sprintf(
826 880 '<p><em>%s</em></p>',
827 - __('The OTTO API is responding normally. No action required.')
881 + /* translators: %s: OTTO name (whitelabel). */
882 + sprintf(__('The %s API is responding normally. No action required.', 'metasync'), Metasync::get_whitelabel_otto_name())
828 883 );
829 884 } else {
830 885 $description .= sprintf(
831 886 '<p><strong>%s</strong></p>' .
@@ -834,19 +889,23 @@
834 889 '<li>%s</li>' .
835 890 '<li>%s</li>' .
836 891 '<li>%s</li>' .
837 892 '</ul>',
838 - __('Frequent rate limiting can degrade OTTO SEO data delivery on your site.'),
839 - __('Recommended Actions:'),
840 - __('Review your OTTO crawl frequency settings in the SearchAtlas dashboard to reduce request volume.'),
841 - __('Check if multiple server processes are triggering OTTO jobs simultaneously.'),
842 - __('Contact SearchAtlas support if rate limiting persists despite low crawl volume.')
893 + /* translators: %s: OTTO name (whitelabel). */
894 + sprintf(__('Frequent rate limiting can degrade %s SEO data delivery on your site.', 'metasync'), Metasync::get_whitelabel_otto_name()),
895 + __('Recommended Actions:', 'metasync'),
896 + /* translators: 1: OTTO name (whitelabel), 2: effective plugin name (whitelabel-aware). */
897 + sprintf(__('Review your %1$s crawl frequency settings in the %2$s dashboard to reduce request volume.', 'metasync'), Metasync::get_whitelabel_otto_name(), Metasync::get_effective_plugin_name()),
898 + /* translators: %s: OTTO name (whitelabel). */
899 + sprintf(__('Check if multiple server processes are triggering %s jobs simultaneously.', 'metasync'), Metasync::get_whitelabel_otto_name()),
900 + /* translators: %s: effective plugin name (whitelabel-aware). */
901 + sprintf(__('Contact %s support if rate limiting persists despite low crawl volume.', 'metasync'), Metasync::get_effective_plugin_name())
843 902 );
844 903
845 904 $description .= sprintf(
846 905 '<p>%s %s</p>',
847 - __( 'Quick link:' ),
848 - $this->get_admin_link( '&tab=general', __( 'Review API Settings' ) )
906 + __( 'Quick link:', 'metasync' ),
907 + $this->get_admin_link( '&tab=general', __( 'Review API Settings', 'metasync' ) )
849 908 );
850 909 }
851 910
852 911 return [
@@ -852,9 +911,9 @@
852 911 return [
853 912 'label' => $label,
854 913 'status' => $status,
855 914 'badge' => [
856 - 'label' => __('MetaSync'),
915 + 'label' => Metasync::get_effective_plugin_name(),
857 916 'color' => $status === 'critical' ? 'red' : ( $status === 'recommended' ? 'orange' : 'green' ),
858 917 ],
859 918 'description' => $description,
860 919 'test' => 'metasync_otto_rate_limit',
@@ -911,17 +970,17 @@
911 970
912 971 // Good state: no debug constants active
913 972 if ( ! $any_debug_on ) {
914 973 return [
915 - 'label' => __('Debug mode is disabled'),
974 + 'label' => __('Debug mode is disabled', 'metasync'),
916 975 'status' => 'good',
917 976 'badge' => [
918 - 'label' => __('MetaSync'),
977 + 'label' => Metasync::get_effective_plugin_name(),
919 978 'color' => 'green',
920 979 ],
921 980 'description' => sprintf(
922 981 '<p>%s</p>',
923 - __('WordPress debug mode is not active. This is the recommended configuration for production sites.')
982 + __('WordPress debug mode is not active. This is the recommended configuration for production sites.', 'metasync')
924 983 ),
925 984 'test' => 'metasync_debug_mode',
926 985 ];
927 986 }
@@ -927,11 +986,11 @@
927 986 }
928 987
929 988 // Recommended state: one or more debug constants are active
930 989 if ( $stats['wp_debug_display'] ) {
931 - $label = __('Debug mode is enabled with error display active');
990 + $label = __('Debug mode is enabled with error display active', 'metasync');
932 991 } else {
933 - $label = __('Debug mode is enabled on this site');
992 + $label = __('Debug mode is enabled on this site', 'metasync');
934 993 }
935 994
936 995 // Status table showing each flag's current state
937 996 $description = sprintf(
@@ -940,15 +999,15 @@
940 999 '<li>%s <strong>%s</strong></li>' .
941 1000 '<li>%s <strong>%s</strong></li>' .
942 1001 '<li>%s <strong>%s</strong></li>' .
943 1002 '</ul>',
944 - __('Active Debug Configuration:'),
945 - __('WP_DEBUG:'),
946 - $stats['wp_debug'] ? __('Enabled') : __('Disabled'),
947 - __('WP_DEBUG_LOG:'),
948 - $stats['wp_debug_log'] ? __('Enabled') : __('Disabled'),
949 - __('WP_DEBUG_DISPLAY:'),
950 - $stats['wp_debug_display'] ? __('Enabled') : __('Disabled')
1003 + __('Active Debug Configuration:', 'metasync'),
1004 + __('WP_DEBUG:', 'metasync'),
1005 + $stats['wp_debug'] ? __('Enabled', 'metasync') : __('Disabled', 'metasync'),
1006 + __('WP_DEBUG_LOG:', 'metasync'),
1007 + $stats['wp_debug_log'] ? __('Enabled', 'metasync') : __('Disabled', 'metasync'),
1008 + __('WP_DEBUG_DISPLAY:', 'metasync'),
1009 + $stats['wp_debug_display'] ? __('Enabled', 'metasync') : __('Disabled', 'metasync')
951 1010 );
952 1011
953 1012 // Call out METASYNC_DEBUG if it is separately active
954 1013 if ( $stats['metasync_debug'] ) {
@@ -953,9 +1012,9 @@
953 1012 // Call out METASYNC_DEBUG if it is separately active
954 1013 if ( $stats['metasync_debug'] ) {
955 1014 $description .= sprintf(
956 1015 '<p>%s</p>',
957 - __('The <code>METASYNC_DEBUG</code> constant is also active. This enables additional MetaSync diagnostic output.')
1016 + __('The <code>METASYNC_DEBUG</code> constant is also active. This enables additional MetaSync diagnostic output.', 'metasync')
958 1017 );
959 1018 }
960 1019
961 1020 // Escalated warning when WP_DEBUG_DISPLAY is on (errors visible to site visitors)
@@ -961,16 +1020,16 @@
961 1020 // Escalated warning when WP_DEBUG_DISPLAY is on (errors visible to site visitors)
962 1021 if ( $stats['wp_debug_display'] ) {
963 1022 $description .= sprintf(
964 1023 '<p><strong>%s</strong> %s</p>',
965 - __('Warning:'),
966 - __('WP_DEBUG_DISPLAY is active. PHP errors and notices may be visible to your site visitors, potentially exposing file paths, database details, and plugin internals. This should be disabled on any publicly accessible site.')
1024 + __('Warning:', 'metasync'),
1025 + __('WP_DEBUG_DISPLAY is active. PHP errors and notices may be visible to your site visitors, potentially exposing file paths, database details, and plugin internals. This should be disabled on any publicly accessible site.', 'metasync')
967 1026 );
968 1027 }
969 1028
970 1029 $description .= sprintf(
971 1030 '<p><em>%s</em></p>',
972 - __('Debug mode is intended for development environments. On a production site, disabling it prevents information leakage and removes the performance overhead of error collection.')
1031 + __('Debug mode is intended for development environments. On a production site, disabling it prevents information leakage and removes the performance overhead of error collection.', 'metasync')
973 1032 );
974 1033
975 1034 $description .= sprintf(
976 1035 '<p><strong>%s</strong></p>' .
@@ -977,17 +1036,17 @@
977 1036 '<ul>' .
978 1037 '<li>%s</li>' .
979 1038 '<li>%s</li>' .
980 1039 '</ul>',
981 - __('Recommended Actions:'),
982 - __('Set <code>define(\'WP_DEBUG\', false);</code> in your wp-config.php if this is a live production site.'),
983 - __('If error logging is needed in production, avoid WP_DEBUG_LOG — it writes to <code>wp-content/debug.log</code> which is publicly accessible via browser and can expose file paths, database details, and API keys. Use a dedicated logging solution that writes outside the webroot instead.')
1040 + __('Recommended Actions:', 'metasync'),
1041 + __('Set <code>define(\'WP_DEBUG\', false);</code> in your wp-config.php if this is a live production site.', 'metasync'),
1042 + __('If error logging is needed in production, avoid WP_DEBUG_LOG — it writes to <code>wp-content/debug.log</code> which is publicly accessible via browser and can expose file paths, database details, and API keys. Use a dedicated logging solution that writes outside the webroot instead.', 'metasync')
984 1043 );
985 1044
986 1045 $description .= sprintf(
987 1046 '<p>%s %s</p>',
988 - __( 'Quick link:' ),
989 - $this->get_admin_link( '&tab=advanced', __( 'Advanced Settings' ) )
1047 + __( 'Quick link:', 'metasync' ),
1048 + $this->get_admin_link( '&tab=advanced', __( 'Advanced Settings', 'metasync' ) )
990 1049 );
991 1050
992 1051 return [
993 1052 'label' => $label,
@@ -992,9 +1051,9 @@
992 1051 return [
993 1052 'label' => $label,
994 1053 'status' => 'recommended',
995 1054 'badge' => [
996 - 'label' => __('MetaSync'),
1055 + 'label' => Metasync::get_effective_plugin_name(),
997 1056 'color' => 'orange',
998 1057 ],
999 1058 'description' => $description,
1000 1059 'test' => 'metasync_debug_mode',
@@ -1015,15 +1074,15 @@
1015 1074 {
1016 1075 // WP-Cron mode
1017 1076 $wp_cron_disabled = defined( 'DISABLE_WP_CRON' ) && DISABLE_WP_CRON;
1018 1077 $wp_cron_mode = $wp_cron_disabled
1019 - ? __( 'System Cron (DISABLE_WP_CRON = true)' )
1020 - : __( 'WP-Cron (default)' );
1078 + ? __( 'System Cron (DISABLE_WP_CRON = true)', 'metasync' )
1079 + : __( 'WP-Cron (default)', 'metasync' );
1021 1080
1022 1081 // PHP max execution time
1023 1082 $max_exec_raw = ini_get( 'max_execution_time' );
1024 1083 $max_exec = $max_exec_raw === '0' || $max_exec_raw === 0
1025 - ? __( 'Unlimited (0)' )
1084 + ? __( 'Unlimited (0)', 'metasync' )
1026 1085 : (int) $max_exec_raw . 's';
1027 1086
1028 1087 // Next scheduled transient cleanup
1029 1088 $next_cleanup_ts = wp_next_scheduled( 'metasync_cleanup_transients' );
@@ -1028,9 +1087,9 @@
1028 1087 // Next scheduled transient cleanup
1029 1088 $next_cleanup_ts = wp_next_scheduled( 'metasync_cleanup_transients' );
1030 1089 $next_cleanup_val = $next_cleanup_ts
1031 1090 ? wp_date( 'Y-m-d H:i:s', $next_cleanup_ts ) . ' (in ' . human_time_diff( $next_cleanup_ts ) . ')'
1032 - : __( 'Not scheduled' );
1091 + : __( 'Not scheduled', 'metasync' );
1033 1092
1034 1093 // Telemetry flush interval label
1035 1094 $flush_interval = Metasync_Telemetry_Config::QUEUE_FLUSH_INTERVAL;
1036 1095 $schedules = wp_get_schedules();
@@ -1039,49 +1098,52 @@
1039 1098 : $flush_interval;
1040 1099
1041 1100 // OTTO suggestions cache TTL (stored in seconds, display as minutes)
1042 1101 $otto_cache_ttl_sec = Metasync_Otto_Config::get_otto_cache_ttl_seconds();
1043 - $otto_cache_ttl_val = ( $otto_cache_ttl_sec / MINUTE_IN_SECONDS ) . ' ' . __( 'minutes' );
1102 + $otto_cache_ttl_val = ( $otto_cache_ttl_sec / MINUTE_IN_SECONDS ) . ' ' . __( 'minutes', 'metasync' );
1044 1103
1045 1104 return [
1046 1105 'perf_wp_cron' => [
1047 - 'label' => __( 'Performance - WP-Cron Mode' ),
1106 + 'label' => __( 'Performance - WP-Cron Mode', 'metasync' ),
1048 1107 'value' => $wp_cron_mode,
1049 1108 ],
1050 1109 'perf_php_max_exec' => [
1051 - 'label' => __( 'Performance - PHP Max Execution Time' ),
1110 + 'label' => __( 'Performance - PHP Max Execution Time', 'metasync' ),
1052 1111 'value' => $max_exec,
1053 1112 ],
1054 1113 'perf_otto_request_timeout' => [
1055 - 'label' => __( 'Performance - OTTO API Request Timeout' ),
1114 + /* translators: %s: OTTO name (whitelabel). */
1115 + 'label' => sprintf(__('Performance - %s API Request Timeout', 'metasync'), Metasync::get_whitelabel_otto_name()),
1056 1116 'value' => '30s',
1057 1117 ],
1058 1118 'perf_otto_cache_ttl' => [
1059 - 'label' => __( 'Performance - OTTO Suggestions Cache TTL' ),
1119 + /* translators: %s: OTTO name (whitelabel). */
1120 + 'label' => sprintf(__('Performance - %s Suggestions Cache TTL', 'metasync'), Metasync::get_whitelabel_otto_name()),
1060 1121 'value' => $otto_cache_ttl_val,
1061 1122 ],
1062 1123 'perf_otto_max_calls' => [
1063 - 'label' => __( 'Performance - OTTO Max API Calls/Min' ),
1124 + /* translators: %s: OTTO name (whitelabel). */
1125 + 'label' => sprintf(__('Performance - %s Max API Calls/Min', 'metasync'), Metasync::get_whitelabel_otto_name()),
1064 1126 'value' => Metasync_Otto_Transient_Cache::MAX_API_CALLS_PER_MINUTE,
1065 1127 ],
1066 1128 'perf_telemetry_queue_max' => [
1067 - 'label' => __( 'Performance - Telemetry Max Queue Size' ),
1129 + 'label' => __( 'Performance - Telemetry Max Queue Size', 'metasync' ),
1068 1130 'value' => Metasync_Telemetry_Config::MAX_QUEUE_SIZE,
1069 1131 ],
1070 1132 'perf_telemetry_batch' => [
1071 - 'label' => __( 'Performance - Telemetry Batch Size' ),
1133 + 'label' => __( 'Performance - Telemetry Batch Size', 'metasync' ),
1072 1134 'value' => Metasync_Telemetry_Config::QUEUE_BATCH_SIZE,
1073 1135 ],
1074 1136 'perf_telemetry_flush' => [
1075 - 'label' => __( 'Performance - Telemetry Queue Flush Interval' ),
1137 + 'label' => __( 'Performance - Telemetry Queue Flush Interval', 'metasync' ),
1076 1138 'value' => $flush_interval_label,
1077 1139 ],
1078 1140 'perf_api_max_retries' => [
1079 - 'label' => __( 'Performance - API Max Retry Attempts' ),
1141 + 'label' => __( 'Performance - API Max Retry Attempts', 'metasync' ),
1080 1142 'value' => Metasync_Telemetry_Config::MAX_RETRY_ATTEMPTS,
1081 1143 ],
1082 1144 'perf_next_cleanup' => [
1083 - 'label' => __( 'Performance - Next Transient Cleanup' ),
1145 + 'label' => __( 'Performance - Next Transient Cleanup', 'metasync' ),
1084 1146 'value' => $next_cleanup_val,
1085 1147 ],
1086 1148 ];
1087 1149 }
@@ -1130,22 +1192,26 @@
1130 1192 $last_hit = $stats['last_hit'];
1131 1193
1132 1194 $last_hit_text = $last_hit
1133 1195 ? sprintf(
1134 - __( 'Last failure: %s' ),
1196 + /* translators: %s: date and time of the last failure. */
1197 + __( 'Last failure: %s', 'metasync' ),
1135 1198 date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $last_hit )
1136 1199 )
1137 - : __( 'No failed actions recorded in the last 24 hours.' );
1200 + : __( 'No failed actions recorded in the last 24 hours.', 'metasync' );
1138 1201
1139 1202 if ( $count > self::FAILED_ACTIONS_THRESHOLD ) {
1140 1203 $status = 'recommended';
1141 1204 $label = sprintf(
1142 - __( 'MetaSync has %d failed SEO processing actions in the last 24 hours' ),
1205 + /* translators: 1: effective plugin name (whitelabel-aware), 2: number of failed actions. */
1206 + __( '%1$s has %2$d failed SEO processing actions in the last 24 hours', 'metasync' ),
1207 + Metasync::get_effective_plugin_name(),
1143 1208 $count
1144 1209 );
1145 1210 } else {
1146 1211 $status = 'good';
1147 - $label = __( 'MetaSync SEO action queue is healthy' );
1212 + /* translators: %s: effective plugin name (whitelabel-aware). */
1213 + $label = sprintf(__('%s SEO action queue is healthy', 'metasync'), Metasync::get_effective_plugin_name());
1148 1214 }
1149 1215
1150 1216 $description = sprintf(
1151 1217 '<p><strong>%s</strong></p>' .
@@ -1152,10 +1218,12 @@
1152 1218 '<ul>' .
1153 1219 '<li>%s <strong>%d</strong></li>' .
1154 1220 '<li>%s</li>' .
1155 1221 '</ul>',
1156 - __( 'MetaSync Failed Actions Statistics (last 24 hours):' ),
1157 - __( 'Failed OTTO SEO processing jobs:' ),
1222 + /* translators: %s: effective plugin name (whitelabel-aware). */
1223 + sprintf(__('%s Failed Actions Statistics (last 24 hours):', 'metasync'), Metasync::get_effective_plugin_name()),
1224 + /* translators: %s: OTTO name (whitelabel). */
1225 + sprintf(__('Failed %s SEO processing jobs:', 'metasync'), Metasync::get_whitelabel_otto_name()),
1158 1226 $count,
1159 1227 $last_hit_text
1160 1228 );
1161 1229
@@ -1161,9 +1229,10 @@
1161 1229
1162 1230 if ( $status === 'good' ) {
1163 1231 $description .= sprintf(
1164 1232 '<p><em>%s</em></p>',
1165 - __( 'OTTO SEO processing jobs are completing successfully. No action required.' )
1233 + /* translators: %s: OTTO name (whitelabel). */
1234 + sprintf(__('%s SEO processing jobs are completing successfully. No action required.', 'metasync'), Metasync::get_whitelabel_otto_name())
1166 1235 );
1167 1236 } else {
1168 1237 $description .= sprintf(
1169 1238 '<p><strong>%s</strong></p>' .
@@ -1171,19 +1240,22 @@
1171 1240 '<li>%s</li>' .
1172 1241 '<li>%s</li>' .
1173 1242 '<li>%s</li>' .
1174 1243 '</ul>',
1175 - __( 'Recommended Actions:' ),
1176 - __( 'Check your SearchAtlas API connection in MetaSync → Settings.' ),
1177 - __( 'Review your PHP error log for OTTO processing exceptions.' ),
1178 - __( 'Verify your OTTO UUID is correctly configured and the SearchAtlas API is reachable.' )
1244 + __( 'Recommended Actions:', 'metasync' ),
1245 + /* translators: 1: effective plugin name (whitelabel-aware). */
1246 + sprintf(__('Check your %1$s API connection in %1$s → Settings.', 'metasync'), Metasync::get_effective_plugin_name()),
1247 + /* translators: %s: OTTO name (whitelabel). */
1248 + sprintf(__('Review your PHP error log for %s processing exceptions.', 'metasync'), Metasync::get_whitelabel_otto_name()),
1249 + /* translators: 1: OTTO name (whitelabel), 2: effective plugin name (whitelabel-aware). */
1250 + sprintf(__('Verify your %1$s UUID is correctly configured and the %2$s API is reachable.', 'metasync'), Metasync::get_whitelabel_otto_name(), Metasync::get_effective_plugin_name())
1179 1251 );
1180 1252
1181 1253 $description .= sprintf(
1182 1254 '<p>%s %s &middot; %s</p>',
1183 - __( 'Quick links:' ),
1184 - $this->get_admin_link( '&tab=general', __( 'Review API Settings' ) ),
1185 - $this->get_admin_link( '-sync-log', __( 'View Changes Log' ) )
1255 + __( 'Quick links:', 'metasync' ),
1256 + $this->get_admin_link( '&tab=general', __( 'Review API Settings', 'metasync' ) ),
1257 + $this->get_admin_link( '-sync-log', __( 'View Changes Log', 'metasync' ) )
1186 1258 );
1187 1259 }
1188 1260
1189 1261 return [
@@ -1189,12 +1261,132 @@
1189 1261 return [
1190 1262 'label' => $label,
1191 1263 'status' => $status,
1192 1264 'badge' => [
1193 - 'label' => __( 'MetaSync' ),
1265 + 'label' => Metasync::get_effective_plugin_name(),
1194 1266 'color' => $status === 'recommended' ? 'orange' : 'green',
1195 1267 ],
1196 1268 'description' => $description,
1197 1269 'test' => 'metasync_failed_actions',
1198 1270 ];
1271 + }
1272 +
1273 + /**
1274 + * Site Health test for OTTO crawl-notify background job reliability
1275 + *
1276 + * Reads the bounded per-URL status store (Metasync_Otto_Job_Status) that
1277 + * the crawl-notify pipeline writes as its background jobs run, so an
1278 + * administrator can see what actually happened to notified URLs — not just
1279 + * that the webhook was acknowledged.
1280 + *
1281 + * Status levels:
1282 + * - good: no failed URLs and fewer than the threshold stuck retrying
1283 + * - recommended: failed URLs exist or retrying count exceeds the threshold
1284 + *
1285 + * When WP-Cron is disabled (DISABLE_WP_CRON) without a visible system
1286 + * crontab entry the pipeline cannot run at all, so an advisory is always
1287 + * included in that case.
1288 + *
1289 + * @since 1.0.0
1290 + * @return array Site Health test result
1291 + */
1292 + public function otto_job_reliability_check()
1293 + {
1294 + $otto_name = Metasync::get_whitelabel_otto_name();
1295 +
1296 + if ( ! class_exists( 'Metasync_Otto_Job_Status' ) ) {
1297 + return [
1298 + /* translators: %s: OTTO name (whitelabel). */
1299 + 'label' => sprintf( __( '%s crawl job tracking is unavailable', 'metasync' ), $otto_name ),
1300 + 'status' => 'good',
1301 + 'badge' => [
1302 + 'label' => Metasync::get_effective_plugin_name(),
1303 + 'color' => 'green',
1304 + ],
1305 + 'description' => '<p>' . esc_html__( 'The status store class is not loaded; nothing to report.', 'metasync' ) . '</p>',
1306 + 'test' => 'metasync_otto_job_reliability',
1307 + ];
1308 + }
1309 +
1310 + $counts = Metasync_Otto_Job_Status::counts();
1311 +
1312 + $retrying_threshold = 25;
1313 + if ( $counts['failed'] > 0 || $counts['retrying'] > $retrying_threshold ) {
1314 + $status = 'recommended';
1315 + $label = sprintf(
1316 + /* translators: 1: OTTO name (whitelabel), 2: number of failed jobs, 3: number of retrying jobs. */
1317 + __( '%1$s crawl jobs need attention (%2$d failed, %3$d retrying)', 'metasync' ),
1318 + $otto_name,
1319 + $counts['failed'],
1320 + $counts['retrying']
1321 + );
1322 + } else {
1323 + $status = 'good';
1324 + /* translators: %s: OTTO name (whitelabel). */
1325 + $label = sprintf( __( '%s crawl jobs are completing normally', 'metasync' ), $otto_name );
1326 + }
1327 +
1328 + $description = sprintf(
1329 + '<p><strong>%s</strong></p><ul><li>%s <strong>%d</strong></li><li>%s <strong>%d</strong></li><li>%s <strong>%d</strong></li><li>%s <strong>%d</strong></li><li>%s <strong>%d</strong></li></ul>',
1330 + /* translators: %s: OTTO name (whitelabel). */
1331 + sprintf( __( '%s crawl job status (last 48 hours):', 'metasync' ), $otto_name ),
1332 + __( 'Accepted, awaiting run:', 'metasync' ),
1333 + $counts['accepted'],
1334 + __( 'Retrying after transient failures:', 'metasync' ),
1335 + $counts['retrying'],
1336 + __( 'Completed:', 'metasync' ),
1337 + $counts['completed'],
1338 + __( 'Failed (retries exhausted):', 'metasync' ),
1339 + $counts['failed'],
1340 + __( 'Queued past the per-batch cap:', 'metasync' ),
1341 + $counts['pending']
1342 + );
1343 +
1344 + if ( $this->constant_is_truthy( 'DISABLE_WP_CRON' ) ) {
1345 + $description .= sprintf(
1346 + '<p><strong>%s</strong> %s</p>',
1347 + __( 'WP-Cron is disabled on this site.', 'metasync' ),
1348 + sprintf(
1349 + /* translators: %s: OTTO product name */
1350 + __( 'Background jobs only run if a system crontab (or equivalent) calls wp-cron.php. Without it, %s crawl notifications are queued but never processed.', 'metasync' ),
1351 + $otto_name
1352 + )
1353 + );
1354 + }
1355 +
1356 + if ( $status !== 'good' ) {
1357 + $description .= sprintf(
1358 + '<p>%s %s &middot; %s</p>',
1359 + __( 'Quick links:', 'metasync' ),
1360 + $this->get_admin_link( '&tab=general', __( 'Review API Settings', 'metasync' ) ),
1361 + $this->get_admin_link( '-sync-log', __( 'View Changes Log', 'metasync' ) )
1362 + );
1363 + }
1364 +
1365 + return [
1366 + 'label' => $label,
1367 + 'status' => $status,
1368 + 'badge' => [
1369 + 'label' => Metasync::get_effective_plugin_name(),
1370 + 'color' => $status === 'recommended' ? 'orange' : 'green',
1371 + ],
1372 + 'description' => $description,
1373 + 'test' => 'metasync_otto_job_reliability',
1374 + ];
1375 + }
1376 +
1377 + /**
1378 + * Whether a named constant is defined and evaluates truthy.
1379 + *
1380 + * The constant name arrives as data so the value is resolved through
1381 + * constant() at runtime; some constants are also loaded from WP stubs
1382 + * with fixed values, which makes a direct `defined() && CONST` check
1383 + * statically redundant even though the live value varies per site.
1384 + *
1385 + * @since 1.0.0
1386 + * @param string $name Constant name, without the leading backslash.
1387 + * @return bool
1388 + */
1389 + private function constant_is_truthy( $name ) {
1390 + return defined( $name ) && filter_var( constant( $name ), FILTER_VALIDATE_BOOLEAN );
1199 1391 }
1200 1392 }