/** * 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(/]*>[\s\S]*?<\/script>/gi, "") .replace(/]*>[\s\S]*?<\/style>/gi, "") .replace(/<[^>]+>/g, " ") .replace(/\s+/g, " ") .trim() } /** * Extract text content from HTML */ export function extractTextContent(html: string): string { return cleanHtmlEntities(stripHtml(html)) } /** * Normalize WordPress image URL (fix malformed URLs) */ function normalizeImageUrl(url: string): string { if (!url) return url // Fix malformed URLs like https:///wp-content -> https://rockymountainvending.com/wp-content if (url.startsWith("https:///") || url.startsWith("http:///")) { return url.replace(/^https?:\/\//, "https://rockymountainvending.com/") } return url } /** * Convert WordPress image URL to local path */ export function getImagePath( originalUrl: string, imageMapping: ImageMapping ): string { // Normalize the URL first const normalizedUrl = normalizeImageUrl(originalUrl) // Try lookup with normalized URL first let mapping = imageMapping[normalizedUrl] // If not found, try with original URL if (!mapping) { mapping = imageMapping[originalUrl] } if (mapping) { // Handle both 'localPath' and 'altText' properties const path = (mapping as any).localPath || (mapping as any).path if (path && !path.startsWith("http")) { return path } } // If we have a normalized URL that's different from original, use it if (normalizedUrl !== originalUrl && normalizedUrl.startsWith("http")) { return normalizedUrl } // Fallback to original URL if not found in mapping return originalUrl } /** * Get alt text for image */ export function getImageAlt( originalUrl: string, imageMapping: ImageMapping, fallback: string = "" ): string { // Normalize the URL first const normalizedUrl = normalizeImageUrl(originalUrl) // Try lookup with normalized URL first let mapping = imageMapping[normalizedUrl] // If not found, try with original URL if (!mapping) { mapping = imageMapping[originalUrl] } if (mapping) { // Handle both 'alt' and 'altText' properties const alt = (mapping as any).alt || (mapping as any).altText if (alt) { return alt } } return fallback || "Vending machine image" }