wip
This commit is contained in:
9
scripts/debug-test.js
Normal file
9
scripts/debug-test.js
Normal file
@@ -0,0 +1,9 @@
|
||||
const { processShortcodes } = require('../lib/html-compat.ts');
|
||||
|
||||
const input = '[vc_row bg_image="”10440″" color_overlay="“#000000”"]content[/vc_row]';
|
||||
console.log('Input:', input);
|
||||
|
||||
const result = processShortcodes(input);
|
||||
console.log('Result:', result);
|
||||
console.log('Contains bg image?', result.includes('background-image'));
|
||||
console.log('Style attribute:', result.match(/style="([^"]*)"/)?.[1]);
|
||||
153
scripts/download-missing-assets.js
Normal file
153
scripts/download-missing-assets.js
Normal file
@@ -0,0 +1,153 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Script to download missing videos and PDFs
|
||||
* Downloads videos referenced in processed data and PDFs linked in pages
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const https = require('https');
|
||||
const http = require('http');
|
||||
|
||||
// Configuration
|
||||
const MEDIA_DIR = path.join(__dirname, '..', 'public', 'media');
|
||||
const PROCESSED_DIR = path.join(__dirname, '..', 'data', 'processed');
|
||||
|
||||
// Videos to download (from home pages)
|
||||
const VIDEOS_TO_DOWNLOAD = [
|
||||
{
|
||||
url: 'https://klz-cables.com/wp-content/uploads/2025/02/header.mp4',
|
||||
filename: 'header.mp4'
|
||||
},
|
||||
{
|
||||
url: 'https://klz-cables.com/wp-content/uploads/2025/02/header.webm',
|
||||
filename: 'header.webm'
|
||||
}
|
||||
];
|
||||
|
||||
// PDFs to download (from terms pages)
|
||||
const PDFS_TO_DOWNLOAD = [
|
||||
{
|
||||
url: 'https://klz-cables.com/wp-content/uploads/2025/01/agbs.pdf',
|
||||
filename: 'agbs.pdf'
|
||||
}
|
||||
];
|
||||
|
||||
// Create media directory if it doesn't exist
|
||||
if (!fs.existsSync(MEDIA_DIR)) {
|
||||
fs.mkdirSync(MEDIA_DIR, { recursive: true });
|
||||
}
|
||||
|
||||
// Download file function
|
||||
function downloadFile(url, filename) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const filePath = path.join(MEDIA_DIR, filename);
|
||||
|
||||
// Check if file already exists
|
||||
if (fs.existsSync(filePath)) {
|
||||
console.log(`✅ Already exists: ${filename}`);
|
||||
resolve(filePath);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`📥 Downloading: ${filename} from ${url}`);
|
||||
|
||||
const protocol = url.startsWith('https') ? https : http;
|
||||
|
||||
const file = fs.createWriteStream(filePath);
|
||||
|
||||
protocol.get(url, (res) => {
|
||||
if (res.statusCode === 200) {
|
||||
res.pipe(file);
|
||||
file.on('finish', () => {
|
||||
console.log(`✅ Downloaded: ${filename}`);
|
||||
resolve(filePath);
|
||||
});
|
||||
} else if (res.statusCode === 301 || res.statusCode === 302) {
|
||||
// Handle redirects
|
||||
if (res.headers.location) {
|
||||
console.log(`🔄 Redirected to: ${res.headers.location}`);
|
||||
downloadFile(res.headers.location, filename).then(resolve).catch(reject);
|
||||
} else {
|
||||
reject(new Error(`Redirect without location: ${res.statusCode}`));
|
||||
}
|
||||
} else {
|
||||
reject(new Error(`Failed to download: HTTP ${res.statusCode}`));
|
||||
}
|
||||
}).on('error', (err) => {
|
||||
fs.unlink(filePath, () => {});
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Main function
|
||||
async function main() {
|
||||
console.log('🔍 Downloading Missing Assets');
|
||||
console.log('==============================');
|
||||
console.log(`Output: ${MEDIA_DIR}`);
|
||||
console.log('');
|
||||
|
||||
const assetMap = {};
|
||||
const downloaded = [];
|
||||
|
||||
// Download videos
|
||||
console.log('🎬 Videos:');
|
||||
for (const video of VIDEOS_TO_DOWNLOAD) {
|
||||
try {
|
||||
await downloadFile(video.url, video.filename);
|
||||
assetMap[video.url] = `/media/${video.filename}`;
|
||||
downloaded.push(video.filename);
|
||||
} catch (error) {
|
||||
console.warn(`⚠️ Failed to download video ${video.filename}:`, error.message);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('');
|
||||
|
||||
// Download PDFs
|
||||
console.log('📄 PDFs:');
|
||||
for (const pdf of PDFS_TO_DOWNLOAD) {
|
||||
try {
|
||||
await downloadFile(pdf.url, pdf.filename);
|
||||
assetMap[pdf.url] = `/media/${pdf.filename}`;
|
||||
downloaded.push(pdf.filename);
|
||||
} catch (error) {
|
||||
console.warn(`⚠️ Failed to download PDF ${pdf.filename}:`, error.message);
|
||||
}
|
||||
}
|
||||
|
||||
// Update asset-map.json with new entries
|
||||
const assetMapPath = path.join(PROCESSED_DIR, 'asset-map.json');
|
||||
if (fs.existsSync(assetMapPath)) {
|
||||
const existingMap = JSON.parse(fs.readFileSync(assetMapPath, 'utf8'));
|
||||
const updatedMap = { ...existingMap, ...assetMap };
|
||||
|
||||
fs.writeFileSync(assetMapPath, JSON.stringify(updatedMap, null, 2));
|
||||
console.log(`\n✅ Updated asset-map.json with ${Object.keys(assetMap).length} new entries`);
|
||||
}
|
||||
|
||||
console.log('\n🎉 Asset Download Complete!');
|
||||
console.log('==============================');
|
||||
console.log(`📥 Downloaded: ${downloaded.length} files`);
|
||||
console.log(`📁 Directory: public/media/`);
|
||||
console.log('');
|
||||
console.log('Files downloaded:');
|
||||
downloaded.forEach(file => {
|
||||
console.log(` - ${file}`);
|
||||
});
|
||||
}
|
||||
|
||||
// Run if called directly
|
||||
if (require.main === module) {
|
||||
main().catch(error => {
|
||||
console.error('\n❌ Script failed:', error.message);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
downloadFile,
|
||||
main
|
||||
};
|
||||
216
scripts/fetch-missing-media.js
Executable file
216
scripts/fetch-missing-media.js
Executable file
@@ -0,0 +1,216 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Script to fetch specific missing media IDs from WordPress
|
||||
* Uses the WordPress REST API to get media URLs and download them
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const https = require('https');
|
||||
|
||||
// Load environment variables
|
||||
require('dotenv').config();
|
||||
|
||||
const BASE_URL = process.env.WOOCOMMERCE_URL;
|
||||
const APP_PASSWORD = process.env.WORDPRESS_APP_PASSWORD;
|
||||
|
||||
// Validate environment
|
||||
if (!BASE_URL || !APP_PASSWORD) {
|
||||
console.error('❌ Missing required environment variables');
|
||||
console.error('Please check .env file for:');
|
||||
console.error(' - WOOCOMMERCE_URL');
|
||||
console.error(' - WORDPRESS_APP_PASSWORD');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Configuration
|
||||
const MISSING_MEDIA_IDS = [10432, 10440, 10382, 10616, 10615, 45569, 10638, 5767];
|
||||
const MEDIA_DIR = path.join(__dirname, '..', 'public', 'media');
|
||||
const RAW_DATA_DIR = path.join(__dirname, '..', 'data', 'raw', '2025-12-30T15-21-49-331Z');
|
||||
|
||||
// Create media directory if it doesn't exist
|
||||
if (!fs.existsSync(MEDIA_DIR)) {
|
||||
fs.mkdirSync(MEDIA_DIR, { recursive: true });
|
||||
}
|
||||
|
||||
// WordPress Auth Header
|
||||
function buildWordPressAuth() {
|
||||
return {
|
||||
'Authorization': `Basic ${Buffer.from(`admin:${APP_PASSWORD}`).toString('base64')}`,
|
||||
'Content-Type': 'application/json'
|
||||
};
|
||||
}
|
||||
|
||||
// Make HTTPS request
|
||||
function makeRequest(url, headers = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const options = {
|
||||
headers: {
|
||||
'User-Agent': 'WordPress-Missing-Media-Fetcher/1.0',
|
||||
...headers
|
||||
}
|
||||
};
|
||||
|
||||
https.get(url, options, (res) => {
|
||||
let data = '';
|
||||
|
||||
res.on('data', (chunk) => {
|
||||
data += chunk;
|
||||
});
|
||||
|
||||
res.on('end', () => {
|
||||
if (res.statusCode >= 200 && res.statusCode < 300) {
|
||||
try {
|
||||
resolve(JSON.parse(data));
|
||||
} catch (e) {
|
||||
resolve(data);
|
||||
}
|
||||
} else {
|
||||
reject(new Error(`HTTP ${res.statusCode}: ${data}`));
|
||||
}
|
||||
});
|
||||
}).on('error', reject);
|
||||
});
|
||||
}
|
||||
|
||||
// Fetch single media item
|
||||
async function fetchMedia(mediaId) {
|
||||
const url = `${BASE_URL}/wp-json/wp/v2/media/${mediaId}`;
|
||||
|
||||
try {
|
||||
console.log(`📥 Fetching media ${mediaId}...`);
|
||||
const media = await makeRequest(url, buildWordPressAuth());
|
||||
return media;
|
||||
} catch (error) {
|
||||
console.error(`❌ Error fetching media ${mediaId}:`, error.message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Download media file
|
||||
function downloadMedia(url, filename) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const filePath = path.join(MEDIA_DIR, filename);
|
||||
|
||||
// Check if file already exists
|
||||
if (fs.existsSync(filePath)) {
|
||||
console.log(`✅ Media already exists: ${filename}`);
|
||||
resolve(filePath);
|
||||
return;
|
||||
}
|
||||
|
||||
const file = fs.createWriteStream(filePath);
|
||||
|
||||
https.get(url, (res) => {
|
||||
if (res.statusCode === 200) {
|
||||
res.pipe(file);
|
||||
file.on('finish', () => {
|
||||
console.log(`✅ Downloaded: ${filename}`);
|
||||
resolve(filePath);
|
||||
});
|
||||
} else {
|
||||
reject(new Error(`Failed to download: ${res.statusCode}`));
|
||||
}
|
||||
}).on('error', (err) => {
|
||||
fs.unlink(filePath, () => {});
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Main function
|
||||
async function main() {
|
||||
console.log('🔍 Fetching Missing Media IDs');
|
||||
console.log('==============================');
|
||||
console.log(`Target: ${BASE_URL}`);
|
||||
console.log(`Output: ${MEDIA_DIR}`);
|
||||
console.log(`Missing IDs: ${MISSING_MEDIA_IDS.join(', ')}`);
|
||||
console.log('');
|
||||
|
||||
const mediaManifest = [];
|
||||
const downloadPromises = [];
|
||||
|
||||
for (const mediaId of MISSING_MEDIA_IDS) {
|
||||
const media = await fetchMedia(mediaId);
|
||||
|
||||
if (media && media.source_url) {
|
||||
const originalFilename = media.source_url.split('/').pop();
|
||||
const filename = `${mediaId}-${originalFilename}`;
|
||||
|
||||
// Add to manifest
|
||||
mediaManifest.push({
|
||||
id: mediaId,
|
||||
url: media.source_url,
|
||||
filename: filename,
|
||||
alt: media.alt_text || '',
|
||||
width: media.media_details?.width,
|
||||
height: media.media_details?.height,
|
||||
mime_type: media.mime_type
|
||||
});
|
||||
|
||||
// Download file
|
||||
downloadPromises.push(
|
||||
downloadMedia(media.source_url, filename).catch(err => {
|
||||
console.warn(`⚠️ Failed to download media ${mediaId}:`, err.message);
|
||||
})
|
||||
);
|
||||
} else {
|
||||
console.warn(`⚠️ Could not fetch media ${mediaId}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for all downloads
|
||||
await Promise.all(downloadPromises);
|
||||
|
||||
// Update media.json
|
||||
const mediaJsonPath = path.join(RAW_DATA_DIR, 'media.json');
|
||||
if (fs.existsSync(mediaJsonPath)) {
|
||||
const existingMedia = JSON.parse(fs.readFileSync(mediaJsonPath, 'utf8'));
|
||||
const updatedMedia = [...existingMedia, ...mediaManifest];
|
||||
|
||||
fs.writeFileSync(
|
||||
mediaJsonPath,
|
||||
JSON.stringify(updatedMedia, null, 2)
|
||||
);
|
||||
console.log(`✅ Updated media.json with ${mediaManifest.length} new items`);
|
||||
} else {
|
||||
console.warn('⚠️ media.json not found, creating new file');
|
||||
fs.writeFileSync(
|
||||
mediaJsonPath,
|
||||
JSON.stringify(mediaManifest, null, 2)
|
||||
);
|
||||
}
|
||||
|
||||
// Update assets.json if needed
|
||||
const assetsJsonPath = path.join(RAW_DATA_DIR, 'assets.json');
|
||||
if (fs.existsSync(assetsJsonPath)) {
|
||||
const assets = JSON.parse(fs.readFileSync(assetsJsonPath, 'utf8'));
|
||||
console.log('✅ Current assets.json:', assets);
|
||||
}
|
||||
|
||||
console.log('\n🎉 Missing Media Fetch Complete!');
|
||||
console.log('==============================');
|
||||
console.log(`📥 Fetched: ${mediaManifest.length} items`);
|
||||
console.log(`📁 Directory: public/media/`);
|
||||
console.log(`📄 Updated: data/raw/2025-12-30T15-21-49-331Z/media.json`);
|
||||
console.log('');
|
||||
console.log('Media items fetched:');
|
||||
mediaManifest.forEach(item => {
|
||||
console.log(` - ${item.id}: ${item.filename}`);
|
||||
});
|
||||
}
|
||||
|
||||
// Run if called directly
|
||||
if (require.main === module) {
|
||||
main().catch(error => {
|
||||
console.error('\n❌ Script failed:', error.message);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
fetchMedia,
|
||||
downloadMedia,
|
||||
main
|
||||
};
|
||||
144
scripts/fix-video-attrs.js
Normal file
144
scripts/fix-video-attrs.js
Normal file
@@ -0,0 +1,144 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Script to move video attributes from excerptHtml to contentHtml
|
||||
* This fixes the issue where video background attributes are in excerptHtml
|
||||
* but ContentRenderer never sees them because it processes contentHtml
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const PROCESSED_DIR = path.join(__dirname, '..', 'data', 'processed');
|
||||
|
||||
// Function to extract video attributes from excerptHtml
|
||||
function extractVideoAttributes(excerptHtml) {
|
||||
if (!excerptHtml) return null;
|
||||
|
||||
// Look for video attributes in vc_row elements
|
||||
const videoMp4Match = excerptHtml.match(/video_mp4="([^"]*)"/i);
|
||||
const videoWebmMatch = excerptHtml.match(/video_webm="([^"]*)"/i);
|
||||
const videoBgMatch = excerptHtml.match(/video_bg="([^"]*)"/i);
|
||||
|
||||
// Also check for data attributes
|
||||
const dataVideoMp4Match = excerptHtml.match(/data-video-mp4="([^"]*)"/i);
|
||||
const dataVideoWebmMatch = excerptHtml.match(/data-video-webm="([^"]*)"/i);
|
||||
const dataVideoBgMatch = excerptHtml.match(/data-video-bg="([^"]*)"/i);
|
||||
|
||||
const videoMp4 = videoMp4Match?.[1] || dataVideoMp4Match?.[1] || '';
|
||||
const videoWebm = videoWebmMatch?.[1] || dataVideoWebmMatch?.[1] || '';
|
||||
const videoBg = videoBgMatch?.[1] || dataVideoBgMatch?.[1] || '';
|
||||
|
||||
if (videoMp4 || videoWebm || videoBg) {
|
||||
return { videoMp4, videoWebm, videoBg };
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Function to merge video attributes into contentHtml
|
||||
function mergeVideoAttributes(contentHtml, videoAttrs) {
|
||||
if (!contentHtml || !videoAttrs) return contentHtml;
|
||||
|
||||
let merged = contentHtml;
|
||||
|
||||
// Find the first vc-row element in contentHtml
|
||||
const vcRowRegex = /<div class="vc-row[^"]*"[^>]*>/i;
|
||||
const match = merged.match(vcRowRegex);
|
||||
|
||||
if (match) {
|
||||
const existingDiv = match[0];
|
||||
let newDiv = existingDiv;
|
||||
|
||||
// Add video attributes if they don't already exist
|
||||
if (videoAttrs.videoMp4 && !existingDiv.includes('video_mp4=') && !existingDiv.includes('data-video-mp4=')) {
|
||||
newDiv = newDiv.replace('>', ` video_mp4="${videoAttrs.videoMp4}">`);
|
||||
}
|
||||
|
||||
if (videoAttrs.videoWebm && !existingDiv.includes('video_webm=') && !existingDiv.includes('data-video-webm=')) {
|
||||
newDiv = newDiv.replace('>', ` video_webm="${videoAttrs.videoWebm}">`);
|
||||
}
|
||||
|
||||
if (videoAttrs.videoBg && !existingDiv.includes('video_bg=') && !existingDiv.includes('data-video-bg=')) {
|
||||
newDiv = newDiv.replace('>', ` video_bg="${videoAttrs.videoBg}">`);
|
||||
}
|
||||
|
||||
// Also add data attributes for better compatibility
|
||||
if (videoAttrs.videoMp4 && !existingDiv.includes('data-video-mp4=')) {
|
||||
newDiv = newDiv.replace('>', ` data-video-mp4="${videoAttrs.videoMp4}">`);
|
||||
}
|
||||
|
||||
if (videoAttrs.videoWebm && !existingDiv.includes('data-video-webm=')) {
|
||||
newDiv = newDiv.replace('>', ` data-video-webm="${videoAttrs.videoWebm}">`);
|
||||
}
|
||||
|
||||
if (videoAttrs.videoBg && !existingDiv.includes('data-video-bg=')) {
|
||||
newDiv = newDiv.replace('>', ` data-video-bg="${videoAttrs.videoBg}">`);
|
||||
}
|
||||
|
||||
merged = merged.replace(existingDiv, newDiv);
|
||||
}
|
||||
|
||||
return merged;
|
||||
}
|
||||
|
||||
// Main function
|
||||
function main() {
|
||||
console.log('🎬 Fixing video attributes in processed data...\n');
|
||||
|
||||
// Load pages.json
|
||||
const pagesPath = path.join(PROCESSED_DIR, 'pages.json');
|
||||
if (!fs.existsSync(pagesPath)) {
|
||||
console.error('❌ pages.json not found');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const pages = JSON.parse(fs.readFileSync(pagesPath, 'utf8'));
|
||||
let fixedCount = 0;
|
||||
|
||||
// Process each page
|
||||
const updatedPages = pages.map(page => {
|
||||
const videoAttrs = extractVideoAttributes(page.excerptHtml);
|
||||
|
||||
if (videoAttrs) {
|
||||
console.log(`📄 Page: ${page.slug} (${page.locale})`);
|
||||
console.log(` Found video attrs in excerpt: mp4="${videoAttrs.videoMp4}" webm="${videoAttrs.videoWebm}"`);
|
||||
|
||||
// Merge into contentHtml
|
||||
const originalContent = page.contentHtml;
|
||||
page.contentHtml = mergeVideoAttributes(page.contentHtml, videoAttrs);
|
||||
|
||||
if (page.contentHtml !== originalContent) {
|
||||
console.log(` ✅ Merged into contentHtml`);
|
||||
fixedCount++;
|
||||
} else {
|
||||
console.log(` ⚠️ Already present or no vc-row found`);
|
||||
}
|
||||
console.log('');
|
||||
}
|
||||
|
||||
return page;
|
||||
});
|
||||
|
||||
// Save updated pages
|
||||
fs.writeFileSync(pagesPath, JSON.stringify(updatedPages, null, 2));
|
||||
|
||||
// Also update the main wordpress-data.json if it exists
|
||||
const wordpressDataPath = path.join(PROCESSED_DIR, 'wordpress-data.json');
|
||||
if (fs.existsSync(wordpressDataPath)) {
|
||||
const wordpressData = JSON.parse(fs.readFileSync(wordpressDataPath, 'utf8'));
|
||||
if (wordpressData.content && wordpressData.content.pages) {
|
||||
wordpressData.content.pages = updatedPages;
|
||||
fs.writeFileSync(wordpressDataPath, JSON.stringify(wordpressData, null, 2));
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`✅ Fixed ${fixedCount} pages with video attributes`);
|
||||
console.log('📁 Files updated:');
|
||||
console.log(` ${pagesPath}`);
|
||||
console.log(` ${wordpressDataPath}`);
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
main();
|
||||
}
|
||||
1262
scripts/process-data-with-bg-images.js
Executable file
1262
scripts/process-data-with-bg-images.js
Executable file
File diff suppressed because it is too large
Load Diff
68
scripts/update-asset-map.js
Executable file
68
scripts/update-asset-map.js
Executable file
@@ -0,0 +1,68 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Script to update asset-map.json with new media entries
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
// Configuration
|
||||
const RAW_DATA_DIR = path.join(__dirname, '..', 'data', 'raw', '2025-12-30T15-21-49-331Z');
|
||||
const PROCESSED_DATA_DIR = path.join(__dirname, '..', 'data', 'processed');
|
||||
|
||||
// New media IDs to add
|
||||
const NEW_MEDIA_IDS = [10432, 10440, 10382, 10616, 10615, 45569, 10638];
|
||||
|
||||
function updateAssetMap() {
|
||||
console.log('🔄 Updating asset-map.json with new media entries');
|
||||
|
||||
// Load current media.json
|
||||
const mediaJsonPath = path.join(RAW_DATA_DIR, 'media.json');
|
||||
const mediaData = JSON.parse(fs.readFileSync(mediaJsonPath, 'utf8'));
|
||||
|
||||
// Load current asset-map.json
|
||||
const assetMapPath = path.join(PROCESSED_DATA_DIR, 'asset-map.json');
|
||||
let assetMap = {};
|
||||
|
||||
if (fs.existsSync(assetMapPath)) {
|
||||
assetMap = JSON.parse(fs.readFileSync(assetMapPath, 'utf8'));
|
||||
}
|
||||
|
||||
// Add new entries
|
||||
let addedCount = 0;
|
||||
NEW_MEDIA_IDS.forEach(id => {
|
||||
const mediaEntry = mediaData.find(m => m.id === id);
|
||||
if (mediaEntry) {
|
||||
const localPath = `/media/${mediaEntry.filename}`;
|
||||
assetMap[mediaEntry.url] = localPath;
|
||||
console.log(`✅ Added: ${id} → ${localPath}`);
|
||||
addedCount++;
|
||||
} else {
|
||||
console.warn(`⚠️ Media ID ${id} not found in media.json`);
|
||||
}
|
||||
});
|
||||
|
||||
// Save updated asset-map.json
|
||||
fs.writeFileSync(
|
||||
assetMapPath,
|
||||
JSON.stringify(assetMap, null, 2)
|
||||
);
|
||||
|
||||
console.log(`\n🎉 Asset map updated! Added ${addedCount} new entries`);
|
||||
console.log(`Total entries in asset-map.json: ${Object.keys(assetMap).length}`);
|
||||
|
||||
return assetMap;
|
||||
}
|
||||
|
||||
// Run if called directly
|
||||
if (require.main === module) {
|
||||
try {
|
||||
updateAssetMap();
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to update asset map:', error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { updateAssetMap };
|
||||
145
scripts/update-process-script.js
Normal file
145
scripts/update-process-script.js
Normal file
@@ -0,0 +1,145 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const filePath = path.join(__dirname, 'process-data-with-bg-images.js');
|
||||
let content = fs.readFileSync(filePath, 'utf8');
|
||||
|
||||
// 1. Update processPages to async
|
||||
content = content.replace(
|
||||
'function processPages(pagesEN, pagesDE, translationMapping, mediaMapping, assetMap) {',
|
||||
'async function processPages(pagesEN, pagesDE, translationMapping, mediaMapping, assetMap) {'
|
||||
);
|
||||
|
||||
// 2. Update processPosts to async
|
||||
content = content.replace(
|
||||
'function processPosts(postsEN, postsDE, translationMapping, mediaMapping, assetMap) {',
|
||||
'async function processPosts(postsEN, postsDE, translationMapping, mediaMapping, assetMap) {'
|
||||
);
|
||||
|
||||
// 3. Update main to async
|
||||
content = content.replace(
|
||||
'function main() {',
|
||||
'async function main() {'
|
||||
);
|
||||
|
||||
// 4. Update main() call
|
||||
content = content.replace(
|
||||
'if (require.main === module) {\n main();\n}',
|
||||
'if (require.main === module) {\n main().catch(console.error);\n}'
|
||||
);
|
||||
|
||||
// 5. Update processPages English loop
|
||||
content = content.replace(
|
||||
'pagesEN.forEach(page => {',
|
||||
'for (const page of pagesEN) {'
|
||||
);
|
||||
|
||||
// 6. Update processPages German loop
|
||||
content = content.replace(
|
||||
'pagesDE.forEach(page => {',
|
||||
'for (const page of pagesDE) {'
|
||||
);
|
||||
|
||||
// 7. Add video processing in processPages English
|
||||
content = content.replace(
|
||||
'contentHtml = replaceUrlsWithLocalPaths(contentHtml, assetMap);\n \n let excerptHtml = decodeContent(page.excerptHtml);',
|
||||
'contentHtml = replaceUrlsWithLocalPaths(contentHtml, assetMap);\n \n // Process video attributes and download videos\n const videoResult = await processVideoAttributes(contentHtml);\n contentHtml = videoResult.html;\n \n let excerptHtml = decodeContent(page.excerptHtml);'
|
||||
);
|
||||
|
||||
// 8. Add video processing in processPages German
|
||||
const germanPattern = /contentHtml = replaceUrlsWithLocalPaths\(contentHtml, assetMap\);\n \n let excerptHtml = decodeContent\(page\.excerptHtml\);\n excerptHtml = replaceBgImageIds\(excerptHtml, mediaMapping\);\n excerptHtml = replaceUrlsWithLocalPaths\(excerptHtml, assetMap\);\n \n processed\.push\(\{/;
|
||||
content = content.replace(
|
||||
germanPattern,
|
||||
`contentHtml = replaceUrlsWithLocalPaths(contentHtml, assetMap);
|
||||
|
||||
// Process video attributes and download videos
|
||||
const videoResult = await processVideoAttributes(contentHtml);
|
||||
contentHtml = videoResult.html;
|
||||
|
||||
let excerptHtml = decodeContent(page.excerptHtml);
|
||||
excerptHtml = replaceBgImageIds(excerptHtml, mediaMapping);
|
||||
excerptHtml = replaceUrlsWithLocalPaths(excerptHtml, assetMap);
|
||||
|
||||
processed.push({`
|
||||
);
|
||||
|
||||
// 9. Update processPosts English loop
|
||||
content = content.replace(
|
||||
'postsEN.forEach(post => {',
|
||||
'for (const post of postsEN) {'
|
||||
);
|
||||
|
||||
// 10. Update processPosts German loop
|
||||
content = content.replace(
|
||||
'postsDE.forEach(post => {',
|
||||
'for (const post of postsDE) {'
|
||||
);
|
||||
|
||||
// 11. Add video processing in processPosts English
|
||||
const postsEnglishPattern = /contentHtml = replaceUrlsWithLocalPaths\(contentHtml, assetMap\);\n \n let excerptHtml = decodeContent\(post\.excerptHtml\);\n excerptHtml = replaceBgImageIds\(excerptHtml, mediaMapping\);\n excerptHtml = replaceUrlsWithLocalPaths\(excerptHtml, assetMap\);\n \n processed\.push\(\{/;
|
||||
content = content.replace(
|
||||
postsEnglishPattern,
|
||||
`contentHtml = replaceUrlsWithLocalPaths(contentHtml, assetMap);
|
||||
|
||||
// Process video attributes and download videos
|
||||
const videoResult = await processVideoAttributes(contentHtml);
|
||||
contentHtml = videoResult.html;
|
||||
|
||||
let excerptHtml = decodeContent(post.excerptHtml);
|
||||
excerptHtml = replaceBgImageIds(excerptHtml, mediaMapping);
|
||||
excerptHtml = replaceUrlsWithLocalPaths(excerptHtml, assetMap);
|
||||
|
||||
processed.push({`
|
||||
);
|
||||
|
||||
// 12. Add video processing in processPosts German
|
||||
const postsGermanPattern = /contentHtml = replaceUrlsWithLocalPaths\(contentHtml, assetMap\);\n \n let excerptHtml = decodeContent\(post\.excerptHtml\);\n excerptHtml = replaceBgImageIds\(excerptHtml, mediaMapping\);\n excerptHtml = replaceUrlsWithLocalPaths\(excerptHtml, assetMap\);\n \n processed\.push\(\{[\s\S]*?translation: enMatch \? \{ locale: 'en', id: enMatch\.en \} : null\n \}\);\n \}\n \n return processed;\n\}/;
|
||||
content = content.replace(
|
||||
postsGermanPattern,
|
||||
`contentHtml = replaceUrlsWithLocalPaths(contentHtml, assetMap);
|
||||
|
||||
// Process video attributes and download videos
|
||||
const videoResult = await processVideoAttributes(contentHtml);
|
||||
contentHtml = videoResult.html;
|
||||
|
||||
let excerptHtml = decodeContent(post.excerptHtml);
|
||||
excerptHtml = replaceBgImageIds(excerptHtml, mediaMapping);
|
||||
excerptHtml = replaceUrlsWithLocalPaths(excerptHtml, assetMap);
|
||||
|
||||
processed.push({
|
||||
id: post.id,
|
||||
translationKey: translationKey,
|
||||
locale: 'de',
|
||||
slug: post.slug,
|
||||
path: \`/de/blog/\${post.slug}\`,
|
||||
title: post.titleHtml.replace(/<[^>]*>/g, ''),
|
||||
titleHtml: post.titleHtml,
|
||||
contentHtml: sanitizeHTML(contentHtml),
|
||||
excerptHtml: processExcerptShortcodes(excerptHtml) || generateExcerpt(contentHtml),
|
||||
featuredImage: post.featuredImage,
|
||||
datePublished: post.datePublished,
|
||||
updatedAt: post.updatedAt,
|
||||
translation: enMatch ? { locale: 'en', id: enMatch.en } : null
|
||||
});
|
||||
}
|
||||
|
||||
return processed;
|
||||
}`
|
||||
);
|
||||
|
||||
// 13. Update main() to await processPages and processPosts
|
||||
content = content.replace(
|
||||
'const pages = processPages(pagesEN, pagesDE, translationMapping, mediaMapping, assetMap);\n const posts = processPosts(postsEN, postsDE, translationMapping, mediaMapping, assetMap);',
|
||||
'const pages = await processPages(pagesEN, pagesDE, translationMapping, mediaMapping, assetMap);\n const posts = await processPosts(postsEN, postsDE, translationMapping, mediaMapping, assetMap);'
|
||||
);
|
||||
|
||||
// 14. Update module.exports
|
||||
content = content.replace(
|
||||
'module.exports = {\n processPages,\n processPosts,\n processProducts,\n processProductCategories,\n processMedia,\n generateAssetMap,\n replaceBgImageIds,\n replaceUrlsWithLocalPaths\n};',
|
||||
'module.exports = {\n processPages,\n processPosts,\n processProducts,\n processProductCategories,\n processMedia,\n generateAssetMap,\n replaceBgImageIds,\n replaceUrlsWithLocalPaths,\n processVideoAttributes\n};'
|
||||
);
|
||||
|
||||
fs.writeFileSync(filePath, content);
|
||||
console.log('✅ Updated process-data-with-bg-images.js to be async');
|
||||
@@ -581,8 +581,10 @@ async function exportLogoAndFavicon() {
|
||||
|
||||
const assets = {
|
||||
logo: null,
|
||||
logoSvg: null,
|
||||
favicon: null,
|
||||
appleTouchIcon: null
|
||||
appleTouchIcon: null,
|
||||
siteIconId: null
|
||||
};
|
||||
|
||||
try {
|
||||
@@ -594,16 +596,24 @@ async function exportLogoAndFavicon() {
|
||||
console.log(`📥 Found custom_logo ID: ${settings.custom_logo}`);
|
||||
const logoMedia = await fetchMedia(settings.custom_logo);
|
||||
if (logoMedia && logoMedia.source_url) {
|
||||
const logoFilename = 'logo.webp';
|
||||
const ext = path.extname(logoMedia.source_url);
|
||||
const logoFilename = `logo${ext}`;
|
||||
await downloadMedia(logoMedia.source_url, logoFilename);
|
||||
assets.logo = `/media/${logoFilename}`;
|
||||
console.log(`✅ Logo downloaded: ${logoFilename}`);
|
||||
|
||||
// Check if it's SVG
|
||||
if (logoMedia.mime_type === 'image/svg+xml' || ext === '.svg') {
|
||||
assets.logoSvg = `/media/${logoFilename}`;
|
||||
console.log(`✅ SVG logo detected: ${logoFilename}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Try to get site_icon
|
||||
if (settings.site_icon) {
|
||||
console.log(`📥 Found site_icon ID: ${settings.site_icon}`);
|
||||
assets.siteIconId = settings.site_icon;
|
||||
const iconMedia = await fetchMedia(settings.site_icon);
|
||||
if (iconMedia && iconMedia.source_url) {
|
||||
// Download as favicon.ico
|
||||
@@ -620,26 +630,108 @@ async function exportLogoAndFavicon() {
|
||||
}
|
||||
}
|
||||
|
||||
// If no logo found in settings, try to find it in media
|
||||
// WP CLI Equivalent: wp media list --search=logo --format=json
|
||||
console.log('🔍 WP CLI Equivalent: Searching for logo media...');
|
||||
if (!assets.logo) {
|
||||
console.log('⚠️ No logo found in settings, searching media...');
|
||||
// Try to find logo by filename pattern
|
||||
const allMedia = await fetchWithPagination('media', { per_page: 100 });
|
||||
const logoCandidates = allMedia.filter(m =>
|
||||
m.title?.rendered?.toLowerCase().includes('logo') ||
|
||||
m.slug?.toLowerCase().includes('logo') ||
|
||||
m.source_url?.toLowerCase().includes('logo')
|
||||
);
|
||||
const logoCandidates = allMedia.filter(m => {
|
||||
const title = m.title?.rendered?.toLowerCase() || '';
|
||||
const slug = m.slug?.toLowerCase() || '';
|
||||
const url = m.source_url?.toLowerCase() || '';
|
||||
return title.includes('logo') || slug.includes('logo') || url.includes('logo');
|
||||
});
|
||||
|
||||
if (logoCandidates.length > 0) {
|
||||
const logoMedia = logoCandidates[0];
|
||||
const logoFilename = 'logo.webp';
|
||||
const ext = path.extname(logoMedia.source_url);
|
||||
const logoFilename = `logo${ext}`;
|
||||
await downloadMedia(logoMedia.source_url, logoFilename);
|
||||
assets.logo = `/media/${logoFilename}`;
|
||||
console.log(`✅ Logo found and downloaded: ${logoFilename}`);
|
||||
|
||||
if (logoMedia.mime_type === 'image/svg+xml' || ext === '.svg') {
|
||||
assets.logoSvg = `/media/${logoFilename}`;
|
||||
console.log(`✅ SVG logo found and downloaded: ${logoFilename}`);
|
||||
} else {
|
||||
console.log(`✅ Logo found and downloaded: ${logoFilename}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WP CLI Equivalent: wp media list --mime=image/svg+xml --format=json
|
||||
console.log('🔍 WP CLI Equivalent: Searching for SVG images...');
|
||||
const allMedia = await fetchWithPagination('media', { per_page: 200 });
|
||||
const svgImages = allMedia.filter(m => m.mime_type === 'image/svg+xml');
|
||||
|
||||
if (svgImages.length > 0) {
|
||||
console.log(`📥 Found ${svgImages.length} SVG images`);
|
||||
for (const svg of svgImages) {
|
||||
const filename = `svg-${svg.id}-${path.basename(svg.source_url)}`;
|
||||
await downloadMedia(svg.source_url, filename);
|
||||
console.log(`✅ SVG downloaded: ${filename}`);
|
||||
}
|
||||
}
|
||||
|
||||
// WP CLI Equivalent: wp postmeta list --post_type=any --meta_key~=_vc --format=json
|
||||
console.log('🔍 WP CLI Equivalent: Searching for Salient/VC images...');
|
||||
const salientImages = new Set();
|
||||
|
||||
// Search pages and posts for Visual Composer meta
|
||||
const searchEndpoints = ['pages', 'posts'];
|
||||
for (const endpoint of searchEndpoints) {
|
||||
const items = await fetchWithPagination(endpoint, { per_page: 100 });
|
||||
items.forEach(item => {
|
||||
// Look for VC-related meta
|
||||
if (item.meta) {
|
||||
Object.keys(item.meta).forEach(key => {
|
||||
if (key.includes('_vc') || key.includes('vc_') || key.includes('salient')) {
|
||||
const metaValue = item.meta[key];
|
||||
if (typeof metaValue === 'string') {
|
||||
// Extract URLs from meta value
|
||||
const urlMatches = metaValue.match(/https?:\/\/[^\s"']+/g);
|
||||
if (urlMatches) {
|
||||
urlMatches.forEach(url => salientImages.add(url));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Also check content for images
|
||||
const content = item.content?.rendered || '';
|
||||
const contentUrls = content.match(/https?:\/\/[^\s"']+\.(jpg|jpeg|png|webp|svg)/gi);
|
||||
if (contentUrls) {
|
||||
contentUrls.forEach(url => salientImages.add(url));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Download Salient/VC images
|
||||
if (salientImages.size > 0) {
|
||||
console.log(`📥 Found ${salientImages.size} Salient/VC images`);
|
||||
const salientManifest = [];
|
||||
|
||||
for (const url of salientImages) {
|
||||
try {
|
||||
const filename = `salient-${Date.now()}-${path.basename(url)}`;
|
||||
await downloadMedia(url, filename);
|
||||
salientManifest.push({
|
||||
originalUrl: url,
|
||||
localPath: `/media/${filename}`,
|
||||
filename: filename
|
||||
});
|
||||
console.log(`✅ Salient image downloaded: ${filename}`);
|
||||
} catch (err) {
|
||||
console.warn(`⚠️ Failed to download Salient image ${url}:`, err.message);
|
||||
}
|
||||
}
|
||||
|
||||
// Save Salient images manifest
|
||||
fs.writeFileSync(
|
||||
path.join(OUTPUT_DIR, 'salient-images.json'),
|
||||
JSON.stringify(salientManifest, null, 2)
|
||||
);
|
||||
}
|
||||
|
||||
// If no favicon found, try to download from common locations
|
||||
if (!assets.favicon) {
|
||||
console.log('⚠️ No favicon found in settings, trying common locations...');
|
||||
@@ -744,6 +836,57 @@ async function generateTranslationMapping() {
|
||||
return mapping;
|
||||
}
|
||||
|
||||
async function exportWPCliPostmeta() {
|
||||
console.log('\n📊 EXPORTING WP CLI POSTMETA (VC/Salient)');
|
||||
|
||||
const vcMeta = [];
|
||||
|
||||
try {
|
||||
// Get all pages and posts
|
||||
const pages = await fetchWithPagination('pages', { status: 'publish', per_page: 100 });
|
||||
const posts = await fetchWithPagination('posts', { status: 'publish', per_page: 100 });
|
||||
|
||||
const allItems = [...pages, ...posts];
|
||||
|
||||
console.log(`🔍 Scanning ${allItems.length} items for VC/Salient meta...`);
|
||||
|
||||
allItems.forEach(item => {
|
||||
if (item.meta) {
|
||||
const vcKeys = Object.keys(item.meta).filter(key =>
|
||||
key.includes('_vc') || key.includes('vc_') || key.includes('salient') || key.includes('wpb_')
|
||||
);
|
||||
|
||||
if (vcKeys.length > 0) {
|
||||
vcKeys.forEach(key => {
|
||||
const value = item.meta[key];
|
||||
vcMeta.push({
|
||||
post_id: item.id,
|
||||
post_type: item.type || 'page',
|
||||
post_slug: item.slug,
|
||||
meta_key: key,
|
||||
meta_value: typeof value === 'string' ? value.substring(0, 200) : JSON.stringify(value),
|
||||
full_value: value
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Save VC postmeta
|
||||
fs.writeFileSync(
|
||||
path.join(OUTPUT_DIR, 'vc-postmeta.json'),
|
||||
JSON.stringify(vcMeta, null, 2)
|
||||
);
|
||||
|
||||
console.log(`✅ VC/Salient postmeta: ${vcMeta.length} entries found`);
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Error exporting postmeta:', error.message);
|
||||
}
|
||||
|
||||
return vcMeta;
|
||||
}
|
||||
|
||||
async function generateRedirects() {
|
||||
console.log('\n📊 GENERATING REDIRECT RULES');
|
||||
|
||||
@@ -785,7 +928,7 @@ async function generateRedirects() {
|
||||
|
||||
// Main Execution
|
||||
async function main() {
|
||||
console.log('🚀 WordPress → Next.js Data Export');
|
||||
console.log('🚀 WordPress → Next.js Data Export (WP CLI Enhanced)');
|
||||
console.log('=====================================');
|
||||
console.log(`Target: ${BASE_URL}`);
|
||||
console.log(`Output: ${OUTPUT_DIR}`);
|
||||
@@ -799,10 +942,13 @@ async function main() {
|
||||
await exportProducts();
|
||||
await exportProductCategories();
|
||||
await exportMenus();
|
||||
|
||||
// Step 2: WP CLI Enhanced exports
|
||||
await exportWPCliPostmeta();
|
||||
await exportMedia();
|
||||
await exportLogoAndFavicon();
|
||||
|
||||
// Step 2: Generate mappings and redirects
|
||||
// Step 3: Generate mappings and redirects
|
||||
await generateTranslationMapping();
|
||||
await generateRedirects();
|
||||
|
||||
@@ -812,6 +958,12 @@ async function main() {
|
||||
console.log(`🖼️ Media directory: public/media/`);
|
||||
console.log(`🎨 Logo/Favicon: public/`);
|
||||
console.log('');
|
||||
console.log('WP CLI Features:');
|
||||
console.log('✓ SVG logo detection and download');
|
||||
console.log('✓ All SVG images exported');
|
||||
console.log('✓ Salient/VC postmeta extracted');
|
||||
console.log('✓ All media downloaded locally');
|
||||
console.log('');
|
||||
console.log('Next steps:');
|
||||
console.log('1. Review exported data for completeness');
|
||||
console.log('2. Check for any missing translations');
|
||||
@@ -838,6 +990,7 @@ module.exports = {
|
||||
exportMedia,
|
||||
exportSiteInfo,
|
||||
exportLogoAndFavicon,
|
||||
exportWPCliPostmeta,
|
||||
generateTranslationMapping,
|
||||
generateRedirects
|
||||
};
|
||||
Reference in New Issue
Block a user