'Post Generation',
'internal_link' => 'Internal Links',
'keyword_extraction' => 'Keyword Extraction',
'site_generation' => 'Site Generation',
];
private const STATUS_COLORS = [
'pending' => '#0073aa',
'processing' => '#f0b849',
'done' => '#46b450',
'failed' => '#dc3232',
];
private const STATUS_ICONS = [
'pending' => '⏳',
'processing' => '⚙️',
'done' => '✓',
'failed' => '✗',
];
public static function formatJobType(string $jobType): string
{
return self::JOB_TYPE_LABELS[$jobType] ?? ucwords(str_replace('_', ' ', $jobType));
}
public static function formatStatus(string $status): string
{
$icon = self::STATUS_ICONS[$status] ?? '';
$label = ucfirst($status);
$color = self::STATUS_COLORS[$status] ?? '#000';
return sprintf(
'%s %s',
esc_attr($color),
$icon,
esc_html($label)
);
}
public static function formatDuration(?int $seconds): string
{
if ($seconds === null || $seconds < 0) {
return 'N/A';
}
if ($seconds < 60) {
return sprintf('%ds', $seconds);
}
if ($seconds < 3600) {
$minutes = floor($seconds / 60);
$secs = $seconds % 60;
return sprintf('%dm %ds', $minutes, $secs);
}
$hours = floor($seconds / 3600);
$minutes = floor(($seconds % 3600) / 60);
return sprintf('%dh %dm', $hours, $minutes);
}
public static function formatPayloadSummary(string $payloadJson): string
{
$payload = json_decode($payloadJson, true);
if (!is_array($payload)) {
return 'Invalid payload';
}
$parts = [];
if (isset($payload['keyword_id'])) {
$parts[] = sprintf('Keyword ID: %d', $payload['keyword_id']);
}
if (isset($payload['post_id'])) {
$parts[] = sprintf('Post ID: %d', $payload['post_id']);
}
if (isset($payload['keyword'])) {
$parts[] = sprintf('ContaiKeyword: "%s"', esc_html($payload['keyword']));
}
if (isset($payload['title'])) {
$parts[] = sprintf('Title: "%s"', esc_html(self::truncate($payload['title'], 50)));
}
if (isset($payload['niche'])) {
$parts[] = sprintf('Niche: %s', esc_html($payload['niche']));
}
if (isset($payload['posts_count'])) {
$parts[] = sprintf('Posts: %d', $payload['posts_count']);
}
return !empty($parts) ? implode(' | ', $parts) : 'No details';
}
public static function formatPriority(int $priority): string
{
if ($priority >= 10) {
return sprintf('High (%d)', $priority);
}
if ($priority >= 5) {
return sprintf('Medium (%d)', $priority);
}
return sprintf('Normal (%d)', $priority);
}
public static function formatAttempts(int $attempts, int $maxAttempts): string
{
$percentage = $maxAttempts > 0 ? ($attempts / $maxAttempts) * 100 : 0;
if ($percentage >= 80) {
$color = '#dc3232';
} elseif ($percentage >= 50) {
$color = '#f0b849';
} else {
$color = '#46b450';
}
return sprintf(
'%d / %d',
$color,
$attempts,
$maxAttempts
);
}
public static function formatDateTime(?string $datetime): string
{
if (empty($datetime)) {
return 'N/A';
}
$timestamp = strtotime($datetime);
$diff = time() - $timestamp;
if ($diff < 60) {
return sprintf('%d seconds ago', $diff);
}
if ($diff < 3600) {
return sprintf('%d minutes ago', floor($diff / 60));
}
if ($diff < 86400) {
return sprintf('%d hours ago', floor($diff / 3600));
}
return gmdate('Y-m-d H:i:s', $timestamp);
}
public static function formatRelativeTime(?string $datetime): string
{
if (empty($datetime)) {
return 'N/A';
}
return human_time_diff(strtotime($datetime), current_time('timestamp')) . ' ago';
}
public static function getStatusBadgeClass(string $status): string
{
$classes = [
'pending' => 'contai-badge-info',
'processing' => 'contai-badge-warning',
'done' => 'contai-badge-success',
'failed' => 'contai-badge-danger',
];
return $classes[$status] ?? 'contai-badge-default';
}
public static function isJobStuck(array $job, int $thresholdMinutes = 30): bool
{
if ($job['status'] !== 'processing' || empty($job['processed_at'])) {
return false;
}
$processedTime = strtotime($job['processed_at']);
$elapsedMinutes = (time() - $processedTime) / 60;
return $elapsedMinutes > $thresholdMinutes;
}
private static function truncate(string $text, int $length = 50): string
{
if (strlen($text) <= $length) {
return $text;
}
return substr($text, 0, $length) . '...';
}
}