/**
* Utilities for converting WordPress HTML content to React components
*/
import Image from 'next/image';
import { ReactNode } from 'react';
export interface WordPressImage {
originalUrl: string;
localPath: string;
alt: string;
needsAltText: boolean;
}
export interface ImageMapping {
[originalUrl: string]: WordPressImage;
}
/**
* Load image mapping
*/
export function loadImageMapping(): ImageMapping {
try {
// Use dynamic import for fs in Next.js server components
const fs = require('fs');
const path = require('path');
// In Next.js, process.cwd() returns the code directory (where Next.js runs from)
const mappingPath = path.join(process.cwd(), 'lib', 'wordpress-data', 'image-mapping.json');
if (!fs.existsSync(mappingPath)) {
console.warn('Image mapping file not found at:', mappingPath);
return {};
}
const mappingData = JSON.parse(fs.readFileSync(mappingPath, 'utf8'));
const mapping: ImageMapping = {};
// Handle both array and object formats
if (Array.isArray(mappingData)) {
mappingData.forEach((img: any) => {
if (img && img.originalUrl) {
// Map the structure to match WordPressImage interface
mapping[img.originalUrl] = {
originalUrl: img.originalUrl,
localPath: img.localPath || img.path || '',
alt: img.alt || img.altText || '',
needsAltText: img.needsAltText || false,
};
}
});
} else if (typeof mappingData === 'object' && mappingData !== null) {
Object.assign(mapping, mappingData);
}
return mapping;
} catch (e) {
console.warn('Could not load image mapping:', e);
// Return empty object instead of throwing
return {};
}
}
/**
* Clean HTML entities
*/
export function cleanHtmlEntities(text: string): string {
if (!text || typeof text !== 'string') {
return '';
}
return text
// First, handle HTML entities
.replace(/’/g, "'")
.replace(/‘/g, "'")
.replace(/“/g, '"')
.replace(/”/g, '"')
.replace(/–/g, '–')
.replace(/—/g, '—')
.replace(/&/g, '&')
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, "'")
.replace(/ /g, ' ')
.replace(/…/g, '...')
.replace(/\[…\]/g, '...')
// Remove any remaining HTML tags (except those we want to preserve in dangerouslySetInnerHTML contexts)
// This strips out any stray tags that shouldn't be in plain text content
.replace(/<(?!\/?(strong|b|em|i|a)\b)[^>]+>/gi, '')
.trim();
}
/**
* Clean HTML from headings - strips ALL HTML tags and entities
* Use this for headings where we never want any HTML markup
*/
export function cleanHeadingText(text: string): string {
if (!text || typeof text !== 'string') {
return '';
}
return text
// First, handle HTML entities
.replace(/’/g, "'")
.replace(/‘/g, "'")
.replace(/“/g, '"')
.replace(/”/g, '"')
.replace(/–/g, '–')
.replace(/—/g, '—')
.replace(/&/g, '&')
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, "'")
.replace(/ /g, ' ')
.replace(/…/g, '...')
.replace(/\[…\]/g, '...')
// Remove ALL HTML tags - no exceptions for headings
.replace(/<[^>]+>/g, '')
// Clean up any leftover whitespace
.replace(/\s+/g, ' ')
.trim();
}
/**
* Strip HTML tags and get clean text
*/
export function stripHtml(html: string): string {
if (!html || typeof html !== 'string') {
return '';
}
return html
.replace(/