airsrefe_get_processed_posts_count(),
'posts_7d' => count(airsrefe_get_processed_posts(['date_query' => [['after' => '7 days ago']]])),
'posts_30d' => count(airsrefe_get_processed_posts(['date_query' => [['after' => '30 days ago']]]))
];
wp_cache_set($cache_key, $cached, 'airsrefe_plugin', HOUR_IN_SECONDS);
}
return $cached;
}
function airsrefe_render_nav_menu($active_tab) {
$nav_items = [
'dashboard' => ['📊', __('Dashboard', 'ai-rss-rewriter')],
'feeds' => ['📰', __('RSS Feeds', 'ai-rss-rewriter')],
'prompts' => ['🤖', __('AI Prompts', 'ai-rss-rewriter')],
'settings' => ['⚙️', __('Settings', 'ai-rss-rewriter')],
'stats' => ['📈', __('Statistics', 'ai-rss-rewriter')],
'logs' => ['📋', __('Logs', 'ai-rss-rewriter')]
];
echo '';
}
function airsrefe_render_stat_card($title, $icon, $value, $subtitle, $color = 'green') {
printf(
'
' .
'' .
'
%s
' .
'
↗ %s
' .
'
',
esc_html($title),
esc_attr($color),
esc_html($icon),
esc_html($value),
esc_html($subtitle)
);
}
add_action('admin_menu', 'airsrefe_add_admin_menu');
add_action('admin_enqueue_scripts', 'airsrefe_admin_scripts');
add_action('admin_notices', 'airsrefe_admin_notices');
add_action('admin_head', 'airsrefe_set_current_submenu');
function airsrefe_add_admin_menu() {
// Add main menu page
add_menu_page(
'AI RSS Rewriter',
'AI RSS Rewriter',
'manage_options',
'ai-rss-rewriter',
'airsrefe_options_page',
airsrefe_get_logo_svg_base64(),
30
);
// Add submenu pages
add_submenu_page(
'ai-rss-rewriter',
__('Dashboard', 'ai-rss-rewriter'),
__('Dashboard', 'ai-rss-rewriter'),
'manage_options',
'ai-rss-rewriter',
'airsrefe_options_page'
);
add_submenu_page(
'ai-rss-rewriter',
__('RSS Feeds', 'ai-rss-rewriter'),
__('RSS Feeds', 'ai-rss-rewriter'),
'manage_options',
'ai-rss-rewriter&tab=feeds',
'airsrefe_options_page'
);
add_submenu_page(
'ai-rss-rewriter',
__('AI Prompts', 'ai-rss-rewriter'),
__('AI Prompts', 'ai-rss-rewriter'),
'manage_options',
'ai-rss-rewriter&tab=prompts',
'airsrefe_options_page'
);
add_submenu_page(
'ai-rss-rewriter',
__('Settings', 'ai-rss-rewriter'),
__('Settings', 'ai-rss-rewriter'),
'manage_options',
'ai-rss-rewriter&tab=settings',
'airsrefe_options_page'
);
add_submenu_page(
'ai-rss-rewriter',
__('Statistics', 'ai-rss-rewriter'),
__('Statistics', 'ai-rss-rewriter'),
'manage_options',
'ai-rss-rewriter&tab=stats',
'airsrefe_options_page'
);
add_submenu_page(
'ai-rss-rewriter',
__('Logs', 'ai-rss-rewriter'),
__('Logs', 'ai-rss-rewriter'),
'manage_options',
'ai-rss-rewriter&tab=logs',
'airsrefe_options_page'
);
}
function airsrefe_get_logo_svg_base64() {
$svg = ' ';
return 'data:image/svg+xml;base64,' . base64_encode($svg);
}
function airsrefe_set_current_submenu() {
global $submenu_file;
$current_page = '';
$current_tab = 'dashboard';
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Admin page navigation parameter, no nonce needed for read-only navigation
if (isset($_GET['page'])) {
// SECURITY: Sanitize page parameter
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Admin page navigation parameter, no nonce needed for read-only navigation
$current_page = sanitize_text_field(wp_unslash($_GET['page']));
}
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Admin tab navigation parameter, no nonce needed for read-only navigation
if (isset($_GET['tab']) && !empty($current_page)) {
// SECURITY: Sanitize tab parameter
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Admin tab navigation parameter, no nonce needed for read-only navigation
$current_tab = sanitize_text_field(wp_unslash($_GET['tab']));
}
if ($current_page === 'ai-rss-rewriter') {
// Map tabs to submenu file names
$tab_to_submenu = [
'dashboard' => 'ai-rss-rewriter',
'feeds' => 'ai-rss-rewriter&tab=feeds',
'prompts' => 'ai-rss-rewriter&tab=prompts',
'settings' => 'ai-rss-rewriter&tab=settings',
'stats' => 'ai-rss-rewriter&tab=stats',
'logs' => 'ai-rss-rewriter&tab=logs'
];
if (isset($tab_to_submenu[$current_tab])) {
$submenu_file = $tab_to_submenu[$current_tab];
}
}
}
function airsrefe_admin_scripts($hook) {
if ($hook !== 'toplevel_page_ai-rss-rewriter') {
return;
}
// Assets are now handled by AIRSREFE_Assets_Manager
// This function is kept for backward compatibility and additional localization
wp_localize_script('airsrefe-admin-modern', 'airsrefe_ajax', [
'nonce' => wp_create_nonce('airsrefe_ajax'),
'ajax_url' => admin_url('admin-ajax.php'),
'ajaxurl' => admin_url('admin-ajax.php'),
'strings' => [
'confirm_delete' => __('Are you sure you want to delete this item?', 'ai-rss-rewriter'),
'processing' => __('Processing...', 'ai-rss-rewriter'),
'saved' => __('Saved', 'ai-rss-rewriter'),
'error' => __('Error', 'ai-rss-rewriter'),
'select_action' => __('Please select an action', 'ai-rss-rewriter'),
'select_items' => __('Please select at least one item', 'ai-rss-rewriter')
]
]);
wp_localize_script('airsrefe-prompts', 'airsrefe_prompts', [
'nonce' => wp_create_nonce('airsrefe_ajax'),
'ajax_url' => admin_url('admin-ajax.php'),
'ajaxurl' => admin_url('admin-ajax.php'),
'editPrompt' => __('Edit Prompt', 'ai-rss-rewriter'),
'saving' => __('Saving...', 'ai-rss-rewriter'),
'resetConfirm' => __('Are you sure you want to reset all prompts to defaults? This action cannot be undone.', 'ai-rss-rewriter'),
'resetFailed' => __('Failed to reset prompts', 'ai-rss-rewriter'),
'loadFailed' => __('Failed to load prompt', 'ai-rss-rewriter'),
'saveFailed' => __('Failed to save prompt', 'ai-rss-rewriter'),
'saveSuccess' => __('Prompt saved successfully', 'ai-rss-rewriter')
]);
}
function airsrefe_options_page() {
// SECURITY FIX: Add capability check
if (!current_user_can('manage_options')) {
wp_die(esc_html__('You do not have sufficient permissions to access this page.', 'ai-rss-rewriter'));
}
$active_tab = airsrefe_get_validated_tab();
echo '';
}
function airsrefe_render_add_feed_modal() {
?>
0 ? round(($successful_posts / count($logs)) * 100) : 0;
echo '';
airsrefe_render_stat_card(__('Total Posts', 'ai-rss-rewriter'), '📄', number_format($posts_count), __('Last 30 days', 'ai-rss-rewriter'), 'green');
/* translators: %d: total number of feeds */
airsrefe_render_stat_card(__('Active Feeds', 'ai-rss-rewriter'), '📡', $active_feeds, sprintf(__('Total: %1$d feeds', 'ai-rss-rewriter'), count($feeds)), 'blue');
airsrefe_render_stat_card(__('AI Processing', 'ai-rss-rewriter'), '🤖', $success_rate . '%', __('Success rate', 'ai-rss-rewriter'), 'purple');
printf(
'
',
esc_html__('Daily Budget', 'ai-rss-rewriter'),
esc_html(number_format($today_cost, 2)),
/* translators: %s: budget limit amount */
esc_html(sprintf(__('Used of $%1$s', 'ai-rss-rewriter'), number_format($budget_limit, 2))),
esc_attr(min(100, airsrefe_safe_ratio($today_cost, $budget_limit, 100)))
);
echo '
';
echo '';
$recent_logs = array_slice(array_reverse($logs), 0, 5);
foreach ($recent_logs as $log) {
$time_ago = human_time_diff(strtotime($log['date'] ?? 'now'), current_time('timestamp'));
$status = ($log['success'] ?? false) ? 'green' : 'orange';
$icon = ($log['success'] ?? false) ? '✓' : '⚠';
printf(
'%s
',
esc_attr($status),
esc_html($icon),
esc_html($log['unique'] ?? $log['original'] ?? 'Unknown'),
esc_html($time_ago),
esc_html__('ago', 'ai-rss-rewriter')
);
}
echo ' ';
echo '';
$preview_feeds = array_slice(array_filter($feeds, function($feed) {
return !isset($feed['enabled']) || $feed['enabled'];
}), 0, 3);
foreach ($preview_feeds as $i => $feed) {
$feed_logs = array_filter($logs, function($log) use ($feed) {
return strpos($log['original'] ?? '', wp_parse_url($feed['url'], PHP_URL_HOST)) !== false;
});
$feed_posts = count($feed_logs);
$feed_success = count(array_filter($feed_logs, function($log) { return $log['success'] ?? false; }));
$feed_success_rate = $feed_posts > 0 ? round(airsrefe_safe_ratio($feed_success, $feed_posts, 100)) : 0;
printf(
'
',
(int)($i),
esc_html__('Run Now', 'ai-rss-rewriter'),
esc_attr(wp_create_nonce('airsrefe_tab_nonce')),
esc_html__('Edit', 'ai-rss-rewriter')
);
}
echo '
';
}
function airsrefe_feeds_tab_modern() {
$feeds = get_option('airsrefe_feeds', []);
if (!empty($feeds)) {
echo '';
}
if (empty($feeds)) {
echo 'RSS
' .
esc_html__('No RSS feeds added yet', 'ai-rss-rewriter') . ' ' .
esc_html__('Add your first RSS feed to start importing content automatically.', 'ai-rss-rewriter') . '
' .
'
+ ' .
esc_html__('Add Your First Feed', 'ai-rss-rewriter') . ' ';
} else {
echo '';
foreach ($feeds as $i => $feed) {
$is_enabled = !isset($feed['enabled']) || $feed['enabled'];
$categories = isset($feed['categories']) ? $feed['categories'] : [$feed['category'] ?? 0];
$disabled_class = !$is_enabled ? 'feed-disabled' : '';
printf(
'
';
echo '
' . esc_html($feed['url']) . '
';
printf(
'
',
esc_html__('Save', 'ai-rss-rewriter'),
(int)($i),
esc_html__('Cancel', 'ai-rss-rewriter')
);
}
echo '
';
}
?>
0 ? round(airsrefe_safe_ratio($successful_posts, $total_posts, 100), 1) : 0;
$daily_costs = get_option('airsrefe_daily_costs', []);
$today_cost = $daily_costs[gmdate('Y-m-d')] ?? 0.00;
$budget_limit = get_option('airsrefe_daily_budget_limit', 10.00);
$budget_usage = $budget_limit > 0 ? airsrefe_safe_ratio($today_cost, $budget_limit, 100) : 0;
$week_cost = 0;
for ($i = 0; $i < 7; $i++) {
$date = gmdate('Y-m-d', strtotime("-$i days"));
$week_cost += $daily_costs[$date] ?? 0;
}
echo '';
airsrefe_render_stat_card(__('Posts Today', 'ai-rss-rewriter'), '📄', (int)($cached_stats['posts_today']), __('Published today', 'ai-rss-rewriter'), 'green');
airsrefe_render_stat_card(__('Posts Last 7 Days', 'ai-rss-rewriter'), '📈', (int)($cached_stats['posts_7d']), __('Weekly total', 'ai-rss-rewriter'), 'blue');
airsrefe_render_stat_card(__('Posts Last 30 Days', 'ai-rss-rewriter'), '📈', (int)($cached_stats['posts_30d']), __('Monthly total', 'ai-rss-rewriter'), 'purple');
airsrefe_render_stat_card(__('Success Rate', 'ai-rss-rewriter'), '📈', esc_html($success_rate) . '%',
/* translators: %1$d: successful posts count, %2$d: total posts count */
sprintf(__('%1$d/%2$d processed', 'ai-rss-rewriter'), (int)($successful_posts), (int)($total_posts)), 'orange');
printf(
'
',
esc_html__('Budget Today', 'ai-rss-rewriter'),
esc_html(number_format($today_cost, 2)),
esc_html(number_format($budget_usage, 1)) . '%',
esc_html__('of budget', 'ai-rss-rewriter'),
esc_attr(min(100, $budget_usage))
);
airsrefe_render_stat_card(
__('Week Costs', 'ai-rss-rewriter'),
'📈',
number_format($week_cost, 2),
__('Last 7 days', 'ai-rss-rewriter'),
'blue'
);
echo '
';
$feeds = get_option('airsrefe_feeds', []);
echo '';
foreach ($feeds as $i => $feed) {
$feed_url = $feed['url'];
$feed_host = wp_parse_url($feed_url, PHP_URL_HOST);
$feed_domain = str_replace('www.', '', $feed_host);
$feed_logs = array_filter($logs, function($log) use ($feed_url, $feed_host, $feed_domain, $i) {
$original = $log['original'] ?? '';
$source_url = $log['source_url'] ?? '';
if (strpos($original, $feed_host) !== false || strpos($original, $feed_domain) !== false) return true;
if (!empty($source_url)) {
$source_host = wp_parse_url($source_url, PHP_URL_HOST);
$source_domain = str_replace('www.', '', $source_host);
if ($source_host === $feed_host || $source_domain === $feed_domain) return true;
}
if (isset($log['feed_url']) && $log['feed_url'] === $feed_url) return true;
if (isset($log['feed_index']) && (int)($log['feed_index']) === (int)($i)) return true;
return false;
});
$feed_posts = count($feed_logs);
$feed_success = count(array_filter($feed_logs, function($log) { return $log['success'] ?? false; }));
$feed_success_rate = $feed_posts > 0 ? round(airsrefe_safe_ratio($feed_success, $feed_posts, 100)) : 0;
if ($feed_posts === 0 && $total_posts > 0) {
// Use a more efficient approach to estimate posts from this feed
$cache_key = 'airsrefe_feed_estimate_' . md5($feed_host);
$estimated_posts = wp_cache_get($cache_key);
if ($estimated_posts === false) {
// Use a more efficient approach to estimate posts from this feed
$recent_posts = get_posts([
'numberposts' => 50, // Get more posts to filter
'date_query' => [['after' => '1 week ago']],
'fields' => 'ids',
'no_found_rows' => true,
'update_post_meta_cache' => false,
'update_post_term_cache' => false,
'cache_results' => false
]);
// Filter posts by source URL in PHP (more efficient)
$feed_posts_count = 0;
foreach ($recent_posts as $post_id) {
$source_url = get_post_meta($post_id, '_airsrefe_source_url', true);
if (!empty($source_url) && strpos($source_url, $feed_host) !== false) {
$feed_posts_count++;
}
}
$estimated_posts = $feed_posts_count;
wp_cache_set($cache_key, $estimated_posts, '', 1800); // Cache for 30 minutes
}
if ($estimated_posts > 0) {
$feed_posts = $estimated_posts;
$feed_success_rate = 85;
}
}
$feed_daily_cost = ($feed_posts > 0 && $total_posts > 0) ? airsrefe_safe_ratio($feed_posts, $total_posts, 1) * $today_cost : 0;
$is_enabled = !isset($feed['enabled']) || $feed['enabled'];
$categories = isset($feed['categories']) ? $feed['categories'] : [$feed['category'] ?? 0];
printf(
'
%s
',
$is_enabled ? '' : 'disabled',
$is_enabled ? 'active' : 'inactive',
esc_html($is_enabled ? __('Active', 'ai-rss-rewriter') : __('Paused', 'ai-rss-rewriter')),
(int)($i) + 1,
esc_html($feed_host)
);
foreach ($categories as $cat_id) {
if ($cat_id == 0) {
echo 'AI ' . esc_html__('Automatic', 'ai-rss-rewriter') . ' ';
} else {
$cat_name = get_cat_name($cat_id);
if ($cat_name) echo '' . esc_html($cat_name) . ' ';
}
}
printf(
'
',
(int)($feed_posts),
esc_html__('Posts', 'ai-rss-rewriter'),
(int)($feed_success_rate),
esc_html__('Success', 'ai-rss-rewriter'),
esc_html(number_format($feed_daily_cost, 3)),
esc_html__('Daily Cost', 'ai-rss-rewriter')
);
}
echo '
';
?>
' .
'
';
$logs = get_option('airsrefe_logs', []);
echo '';
$total_processing_cost = 0;
$successful_processing_cost = 0;
$failed_processing_cost = 0;
$total_articles = count($logs);
$successful_articles = 0;
foreach ($logs as $log) {
if (isset($log['success']) && $log['success']) {
$cost = airsrefe_calculate_processing_cost($log);
$total_processing_cost += $cost;
$successful_processing_cost += $cost;
$successful_articles++;
} else {
$failed_cost = 0.001;
$total_processing_cost += $failed_cost;
$failed_processing_cost += $failed_cost;
}
}
echo '
';
printf(
'
%s: $%s
',
esc_html__('Total Processing Cost', 'ai-rss-rewriter'),
esc_html(number_format($total_processing_cost, 3))
);
printf(
'
%s: $%s
',
esc_html__('Successful Articles Cost', 'ai-rss-rewriter'),
esc_html(number_format($successful_processing_cost, 3))
);
printf(
'
%s: $%s
',
esc_html__('Failed Attempts Cost', 'ai-rss-rewriter'),
esc_html(number_format($failed_processing_cost, 3))
);
printf(
'
%s: $%s
',
esc_html__('Average Cost per Article', 'ai-rss-rewriter'),
esc_html($total_articles > 0 ? number_format($total_processing_cost / $total_articles, 3) : '0.000')
);
echo '
';
if (empty($logs)) {
echo '
Log
' .
esc_html__('No processing records yet', 'ai-rss-rewriter') . ' ' .
esc_html__('Try running some feeds first to see processing history here.', 'ai-rss-rewriter') . '
';
} else {
echo '
' .
esc_html__('Date', 'ai-rss-rewriter') . ' ' .
esc_html__('Original Title', 'ai-rss-rewriter') . ' ' .
esc_html__('Processed Title', 'ai-rss-rewriter') . ' ' .
esc_html__('Status', 'ai-rss-rewriter') . ' ' .
esc_html__('Processing Cost', 'ai-rss-rewriter') . ' ';
$logs = array_reverse($logs);
$display_logs = array_slice($logs, 0, 50);
foreach ($display_logs as $log) {
$status = ($log['success'] ?? false) ?
'' . esc_html__('Success', 'ai-rss-rewriter') . ' ' :
'' . esc_html__('Failed', 'ai-rss-rewriter') . ' ';
$original = $log['original'] ?? 'No title';
$unique = $log['unique'] ?? 'No title';
$processing_cost = 0;
if (isset($log['success']) && $log['success']) {
$processing_cost = airsrefe_calculate_processing_cost($log);
}
$cost_display = $processing_cost > 0 ? '$' . number_format($processing_cost, 3) : '-';
printf(
'%s %s %s %s %s ',
esc_html($log['date'] ?? 'Unknown'),
esc_attr($original),
esc_html(mb_substr($original, 0, 40) . (strlen($original) > 40 ? '...' : '')),
esc_attr($unique),
esc_html(mb_substr($unique, 0, 40) . (strlen($unique) > 40 ? '...' : '')),
wp_kses($status, ['span' => ['class' => []]]),
esc_html($cost_display)
);
}
echo '
';
}
echo '
';
}
function airsrefe_admin_notices() {
if (!current_user_can('manage_options') || !isset($_GET['page']) || $_GET['page'] !== 'ai-rss-rewriter') return;
if (isset($_GET['message']) && isset($_GET['_wpnonce']) && !wp_verify_nonce(sanitize_text_field(wp_unslash($_GET['_wpnonce'])), 'airsrefe_admin_notice')) {
return;
}
$message = isset($_GET['message']) ? sanitize_text_field(wp_unslash($_GET['message'])) : '';
$notices = [
'feed_added' => ['success', __('RSS feed successfully added!', 'ai-rss-rewriter')],
'feed_updated' => ['success', __('RSS feed successfully updated!', 'ai-rss-rewriter')],
'feed_deleted' => ['success', __('RSS feed successfully deleted!', 'ai-rss-rewriter')],
'feed_processed' => ['success', __('RSS feed successfully processed!', 'ai-rss-rewriter')],
'feeds_processed' => ['success', __('Selected feeds successfully processed!', 'ai-rss-rewriter')],
'feeds_enabled' => ['success', __('Selected feeds enabled!', 'ai-rss-rewriter')],
'feeds_disabled' => ['success', __('Selected feeds disabled!', 'ai-rss-rewriter')],
'feeds_deleted' => ['success', __('Selected feeds deleted!', 'ai-rss-rewriter')],
'logs_cleared' => ['success', __('Logs successfully cleared!', 'ai-rss-rewriter')],
'parsing_unblocked' => ['success', __('Parsing successfully unblocked!', 'ai-rss-rewriter')],
'feed_error' => ['error', __('Error processing RSS feed!', 'ai-rss-rewriter')],
'no_selection' => ['warning', __('No feeds or actions selected!', 'ai-rss-rewriter')]
];
if (isset($notices[$message])) {
[$type, $text] = $notices[$message];
echo '';
}
}