supported_extensions = array( 'html', 'htm' );
$this->has_ai_fallback = true;
$this->priority = 11;
}
/**
* Parse HTML files
*
* @param string $file_path Path to the HTML file
* @return array Parsed content data
* @throws Exception If HTML cannot be parsed
*/
public function parse( $file_path ) {
if ( ! is_readable( $file_path ) ) {
throw new Exception( 'HTML file is not readable: ' . esc_html( basename( $file_path ) ) );
}
$html_content = file_get_contents( $file_path );
if ( $html_content === false ) {
throw new Exception( 'Failed to read HTML file contents' );
}
if ( empty( trim( $html_content ) ) ) {
throw new Exception( 'HTML file appears to be empty' );
}
// Parse HTML with DOM parser
$parsed_data = $this->parse_html_content( $html_content );
if ( empty( trim( $parsed_data['content'] ) ) ) {
throw new Exception( 'HTML file contains no extractable text content' );
}
// Sanitize content while preserving some structure
$sanitized_content = $this->sanitize_content( $parsed_data['content'], 'html' );
// Extract title
$title = $parsed_data['title'] ?: pathinfo( $file_path, PATHINFO_FILENAME );
// Generate metadata
$metadata = $this->generate_metadata(
$file_path,
'html',
array(
'original_title' => $parsed_data['title'],
'meta_description' => $parsed_data['meta_description'],
'meta_keywords' => $parsed_data['meta_keywords'],
'heading_structure' => $parsed_data['headings'],
'link_count' => $parsed_data['link_count'],
'image_count' => $parsed_data['image_count'],
'table_count' => $parsed_data['table_count'],
'list_count' => $parsed_data['list_count'],
'word_count' => str_word_count( $sanitized_content ),
'char_count' => strlen( $sanitized_content ),
'language' => $parsed_data['language'],
'encoding' => $parsed_data['encoding'],
)
);
return array(
'content' => $sanitized_content,
'title' => $title,
'metadata' => $metadata,
);
}
/**
* Parse HTML content using DOM parser
*
* @param string $html_content Raw HTML content
* @return array Parsed content and metadata
* @throws Exception If HTML parsing fails
*/
private function parse_html_content( $html_content ) {
// Clean up the HTML first
$html_content = $this->clean_html( $html_content );
$dom = new DOMDocument();
libxml_use_internal_errors( true );
// Load HTML with encoding detection
$encoding = $this->detect_html_encoding( $html_content );
if ( $encoding && $encoding !== 'UTF-8' ) {
$html_content = mb_convert_encoding( $html_content, 'UTF-8', $encoding );
}
$success = $dom->loadHTML( $html_content, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD );
if ( ! $success ) {
throw new Exception( 'Failed to parse HTML content with DOM parser' );
}
$xpath = new DOMXPath( $dom );
// Extract title
$title = $this->extract_html_title( $xpath );
// Extract meta information
$meta_description = $this->extract_meta_content( $xpath, 'description' );
$meta_keywords = $this->extract_meta_content( $xpath, 'keywords' );
$language = $this->extract_html_language( $xpath );
// Extract structured content
$content_data = $this->extract_structured_content( $xpath );
// Count various elements
$link_count = $xpath->query( '//a[@href]' )->length;
$image_count = $xpath->query( '//img[@src]' )->length;
$table_count = $xpath->query( '//table' )->length;
$list_count = $xpath->query( '//ul | //ol' )->length;
return array(
'content' => $content_data['content'],
'title' => $title,
'meta_description' => $meta_description,
'meta_keywords' => $meta_keywords,
'headings' => $content_data['headings'],
'paragraph_count' => $content_data['paragraph_count'],
'link_count' => $link_count,
'image_count' => $image_count,
'table_count' => $table_count,
'list_count' => $list_count,
'language' => $language,
'encoding' => $encoding,
);
}
/**
* Clean HTML content before parsing
*
* @param string $html_content Raw HTML
* @return string Cleaned HTML
*/
private function clean_html( $html_content ) {
// Remove script and style content
$html_content = preg_replace( '/