$score, 'grade' => $grade, 'color' => $color, 'items' => $items, 'runtime_included' => $runtime_included, 'runtime_score' => $runtime_score, 'runtime_time' => $runtime_time, ); } /** * Persist a self-test report so it can feed the score and the digest. * * @param array $report Self-test report rows. */ public static function store_report( array $report ) { update_option( ADG_AIM_OPT_LAST_SELFTEST, array( 'time' => current_time( 'mysql' ), 'report' => $report, ), false ); } /** * Read the stored self-test report if it is still fresh. * * @return array|null */ public static function last_report() { $stored = get_option( ADG_AIM_OPT_LAST_SELFTEST, null ); if ( ! is_array( $stored ) || empty( $stored['time'] ) ) { return null; } $ts = strtotime( (string) $stored['time'] ); if ( ! $ts || ( time() - $ts ) > self::REPORT_MAX_AGE ) { return null; } return $stored; } /* ------------------------------------------------------------------ */ /** * The configuration checklist. * * @return array list of array( label, state(pass|partial|fail), advice, weight ). */ private static function config_items() { $negotiation = (bool) ADG_AIM_Plugin::get_setting( 'negotiation_enabled', true ); $llms = (bool) ADG_AIM_Plugin::get_setting( 'llms_enabled', true ); $schema = (bool) ADG_AIM_Plugin::get_setting( 'schema_enabled', true ); $ipverify = (bool) ADG_AIM_Plugin::get_setting( 'ip_verification', false ); $types = (array) ADG_AIM_Plugin::get_setting( 'post_types', array() ); $items = array(); $items[] = array( 'label' => __( 'Markdown is served to AI crawlers', 'adg-markdown-for-ai-crawlers' ), 'state' => $negotiation ? 'pass' : 'fail', 'advice' => $negotiation ? '' : __( 'Turn on the content-negotiation master switch.', 'adg-markdown-for-ai-crawlers' ), 'weight' => 3, ); $items[] = array( 'label' => __( 'llms.txt / llms-full.txt published', 'adg-markdown-for-ai-crawlers' ), 'state' => $llms ? 'pass' : 'fail', 'advice' => $llms ? '' : __( 'Enable llms.txt so assistants can discover your content index.', 'adg-markdown-for-ai-crawlers' ), 'weight' => 2, ); $items[] = array( 'label' => __( 'At least one content type is exposed', 'adg-markdown-for-ai-crawlers' ), 'state' => empty( $types ) ? 'fail' : 'pass', 'advice' => empty( $types ) ? __( 'Select the post types that should be available as Markdown.', 'adg-markdown-for-ai-crawlers' ) : '', 'weight' => 2, ); $items[] = array( 'label' => __( 'Structured data (Schema.org JSON-LD) attached', 'adg-markdown-for-ai-crawlers' ), 'state' => $schema ? 'pass' : 'partial', 'advice' => $schema ? '' : __( 'Enable JSON-LD front matter to give crawlers machine-readable metadata.', 'adg-markdown-for-ai-crawlers' ), 'weight' => 1, ); $items[] = array( 'label' => __( 'Bot IP verification (anti-spoofing)', 'adg-markdown-for-ai-crawlers' ), 'state' => $ipverify ? 'pass' : 'partial', 'advice' => $ipverify ? '' : __( 'Optional: verify crawler IPs so a spoofed User-Agent cannot pull your Markdown.', 'adg-markdown-for-ai-crawlers' ), 'weight' => 1, ); return $items; } /** * Score a set of weighted items (state → fraction). * * @param array $items Items. * @return float 0..100. */ private static function score_items( array $items ) { $sum = 0.0; $weight = 0.0; foreach ( $items as $item ) { $w = isset( $item['weight'] ) ? (float) $item['weight'] : 1.0; $sum += $w * self::fraction( $item['state'] ); $weight += $w; } return $weight > 0 ? ( $sum / $weight ) * 100 : 0.0; } /** * Score a self-test report (ok/warn/fail → fraction, equal weight). * * @param array $report Report rows. * @return int 0..100. */ private static function score_report( array $report ) { $sum = 0.0; $count = 0; foreach ( $report as $row ) { $status = isset( $row['status'] ) ? $row['status'] : 'warn'; $sum += self::fraction( self::map_status( $status ) ); ++$count; } return $count > 0 ? (int) round( ( $sum / $count ) * 100 ) : 0; } /** * Map a self-test status to a checklist state. * * @param string $status ok|warn|fail. * @return string pass|partial|fail. */ private static function map_status( $status ) { if ( 'ok' === $status ) { return 'pass'; } if ( 'fail' === $status ) { return 'fail'; } return 'partial'; } /** * State → numeric fraction. * * @param string $state pass|partial|fail. * @return float */ private static function fraction( $state ) { if ( 'pass' === $state ) { return 1.0; } if ( 'partial' === $state ) { return 0.5; } return 0.0; } /** * Score → grade label + color. * * @param int $score Score. * @return array [ label, color ]. */ private static function grade( $score ) { if ( $score >= 90 ) { return array( __( 'Excellent', 'adg-markdown-for-ai-crawlers' ), '#00a32a' ); } if ( $score >= 75 ) { return array( __( 'Good', 'adg-markdown-for-ai-crawlers' ), '#2271b1' ); } if ( $score >= 50 ) { return array( __( 'Fair', 'adg-markdown-for-ai-crawlers' ), '#996800' ); } return array( __( 'Needs work', 'adg-markdown-for-ai-crawlers' ), '#d63638' ); } }