Rocky_Mountain_Vending/lib/wordpress-content.ts

233 lines
6 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 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(/&lt;/g, "<")
.replace(/&gt;/g, ">")
.replace(/&quot;/g, '"')
.replace(/&apos;/g, "'")
.replace(/&nbsp;/g, " ")
.replace(/&hellip;/g, "...")
.replace(/\[&hellip;\]/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(/&#8217;/g, "'")
.replace(/&#8216;/g, "'")
.replace(/&#8220;/g, '"')
.replace(/&#8221;/g, '"')
.replace(/&#8211;/g, "")
.replace(/&#8212;/g, "—")
.replace(/&#038;/g, "&")
.replace(/&amp;/g, "&")
.replace(/&lt;/g, "<")
.replace(/&gt;/g, ">")
.replace(/&quot;/g, '"')
.replace(/&apos;/g, "'")
.replace(/&nbsp;/g, " ")
.replace(/&hellip;/g, "...")
.replace(/\[&hellip;\]/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(/<script[^>]*>[\s\S]*?<\/script>/gi, "")
.replace(/<style[^>]*>[\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"
}