Content Audit): counts per check, filterable issue list, * per-row quick fixes. Stock WordPress UI, everything escaped. */ defined('ABSPATH') || exit; class Postlint_Report { public static function init() { add_action('admin_menu', [__CLASS__, 'menu']); add_action('admin_post_postlint_fix', ['Postlint_Fixes', 'handle']); add_action('admin_post_postlint_scan', [__CLASS__, 'handle_scan']); add_action('admin_post_postlint_save_settings', [__CLASS__, 'handle_settings']); add_action('admin_enqueue_scripts', [__CLASS__, 'assets']); } /** The media library picker for the default featured image, on this screen only. */ public static function assets($hook) { if ($hook !== 'tools_page_postlint-report') { return; } wp_enqueue_media(); wp_add_inline_script('media-editor', "jQuery(function($){var f;$('#postlint-img-pick').on('click',function(e){e.preventDefault();f=f||wp.media({title:$(this).data('title'),library:{type:'image'},multiple:false});f.off('select').on('select',function(){var a=f.state().get('selection').first().toJSON(),u=(a.sizes&&a.sizes.thumbnail?a.sizes.thumbnail.url:a.url);$('#postlint-img').val(a.id);$('#postlint-img-preview').html($('',{src:u,alt:'',width:80,height:80,style:'object-fit:cover;border-radius:4px'}));$('#postlint-img-clear').show();});f.open();});$('#postlint-img-clear').on('click',function(e){e.preventDefault();$('#postlint-img').val(0);$('#postlint-img-preview').empty();$(this).hide();});});"); } public static function menu() { add_management_page('Content Audit', 'Content Audit', 'manage_options', 'postlint-report', [__CLASS__, 'render']); } private static function guard() { if (!current_user_can('manage_options')) { wp_die(esc_html__('You are not allowed to do that.', 'postlint-content-audit')); } } public static function handle_scan() { self::guard(); check_admin_referer('postlint_scan'); $settings = Postlint_Settings::get(); $offset = isset($_POST['offset']) ? absint($_POST['offset']) : 0; $scanned = Postlint_Scanner::scan_batch($settings, $offset); $next = $scanned > 0 ? $offset + $scanned : 0; wp_safe_redirect(admin_url('tools.php?page=postlint-report&scanned=' . (int) $scanned . '&next=' . (int) $next)); exit; } public static function handle_settings() { self::guard(); check_admin_referer('postlint_scan'); $raw = isset($_POST['postlint']) && is_array($_POST['postlint']) ? wp_unslash($_POST['postlint']) : []; update_option(POSTLINT_OPTION_SETTINGS, Postlint_Settings::sanitize($raw), false); Postlint_Scheduler::sync((bool) Postlint_Settings::get()['weekly_rescan']); wp_safe_redirect(admin_url('tools.php?page=postlint-report&saved=1')); exit; } /** The issues a view lists: all of them, or only those carrying one check. */ public static function filtered_issues(array $issues, string $filter): array { if ($filter === '') { return $issues; } return array_values(array_filter($issues, static function ($issue) use ($filter) { return in_array($filter, $issue['checks'], true); })); } public static function render() { self::guard(); $settings = Postlint_Settings::get(); $report = Postlint_Scanner::get_report(); $filter = isset($_GET['check']) ? sanitize_key($_GET['check']) : ''; ?>

__('Done.', 'postlint-content-audit'), 'nothing' => __('Nothing to change for that action.', 'postlint-content-audit'), 'missing' => __('That post no longer exists.', 'postlint-content-audit'), ]; $done = [ 'excerpt' => __('Excerpt written for "%s".', 'postlint-content-audit'), 'featured-image' => __('Default featured image set on "%s".', 'postlint-content-audit'), ]; $fixed_post = isset($_GET['postlint_post']) ? get_post(absint($_GET['postlint_post'])) : null; $fixed_what = isset($_GET['postlint_fix']) ? sanitize_key($_GET['postlint_fix']) : ''; if (isset($_GET['postlint_msg']) && $_GET['postlint_msg'] === 'fixed' && $fixed_post && isset($done[$fixed_what])) : ?>

0) { echo esc_html(sprintf('%1$d posts scanned, last scan %2$s (UTC).', (int) $report['scanned'], $report['scanned_at'])); } else { esc_html_e('No scan yet. Run your first scan below.', 'postlint-content-audit'); } ?>

0 && empty($report['complete'])) : ?>

$label) : if (!in_array($code, $settings['checks'], true)) continue; ?>

0; $can_excerpt = in_array('excerpt', $issue['checks'], true); if (!$can_image && !$can_excerpt) : ?>

true], 'names'); unset($types['attachment']); return $types; }