]*>(.*?)<\/p>/is', $html, $m ) ) { foreach ( $m[1] as $p ) { $text = self::text( $p ); if ( '' !== $text ) { $out[] = $text; } } } if ( empty( $out ) ) { // Fallback for content without
tags (some builders): split on double newlines.
$out = array_values( array_filter( array_map( 'trim', preg_split( '/\n{2,}/', self::text( $html ) ) ?: array() ) ) );
}
return $out;
}
/**
* Images with/without alt: [total, missing_alt].
*
* @return array{0:int, 1:int}
*/
public static function images_alt( string $html ): array {
$total = 0;
$missing = 0;
if ( preg_match_all( '/]*>/i', $html, $m ) ) {
foreach ( $m[0] as $img ) {
++$total;
if ( ! preg_match( '/\balt\s*=\s*("([^"]+)"|\'([^\']+)\')/i', $img ) ) {
++$missing;
}
}
}
return array( $total, $missing );
}
/**
* Links split into [internal, external] counts relative to home host.
*
* @return array{0:int, 1:int}
*/
public static function links( string $html ): array {
$internal = 0;
$external = 0;
$home = (string) wp_parse_url( home_url(), PHP_URL_HOST );
if ( preg_match_all( '/]*href\s*=\s*("([^"]+)"|\'([^\']+)\')/i', $html, $m ) ) {
foreach ( $m[2] as $i => $href ) {
$href = '' !== $href ? $href : $m[3][ $i ];
if ( str_starts_with( $href, '#' ) || str_starts_with( $href, 'mailto:' ) || str_starts_with( $href, 'tel:' ) ) {
continue;
}
$host = (string) wp_parse_url( $href, PHP_URL_HOST );
if ( '' === $host || $host === $home ) {
++$internal;
} else {
++$external;
}
}
}
return array( $internal, $external );
}
/**
* Lightweight HTML → markdown for llms-full.txt (headings, lists, paragraphs).
*/
public static function to_markdown( string $html ): string {
$html = preg_replace( '/<(script|style)\b.*?<\/\1>/is', '', $html ) ?? '';
$html = preg_replace_callback(
'/
/i', "\n", $html ) ?? '';
$text = self::text( $html );
// Re-apply markdown newlines lost by text(): text() keeps \n, only collapses spaces.
return trim( (string) preg_replace( "/\n{3,}/", "\n\n", $text ) );
}
}