Files
manoon-headless/scripts/migrate-content.js
Unchained 9ab07ab01d feat: implement centralized taxonomy for programmatic SEO
- Create taxonomy system with oils.json (5 oils) and concerns.json (9 concerns)
- Migrate 10 content files to new data/content/oil-for-concern/ structure
- Add scripts: generate-urls.js, validate-taxonomy.js, migrate-content.js
- Update dataLoader.ts to use centralized taxonomy
- Generate 40 URLs (10 pairs × 4 languages)
- Create sitemap-programmatic.xml for SEO
- Update by-oil and by-concern directory pages
2026-04-09 08:04:35 +02:00

107 lines
3.6 KiB
JavaScript

const fs = require('fs');
const path = require('path');
const oils = require('../data/taxonomy/oils.json');
const concerns = require('../data/taxonomy/concerns.json');
const LOCALES = ['sr', 'en', 'de', 'fr'];
const legacyFiles = [
{ file: 'najbolje-arganovo-ulje-za-bore.json', oil: 'argan-oil', concern: 'wrinkles' },
{ file: 'najbolje-arganovo-ulje-za-suvu-kozu.json', oil: 'argan-oil', concern: 'dry-skin' },
{ file: 'najbolje-arganovo-ulje-za-podocnjake.json', oil: 'argan-oil', concern: 'under-eye-bags' },
{ file: 'najbolje-ulje-divlje-ruze-za-bore.json', oil: 'rosehip-oil', concern: 'wrinkles' },
{ file: 'najbolje-ulje-divlje-ruze-za-tamne-pjege.json', oil: 'rosehip-oil', concern: 'dark-spots' },
{ file: 'najbolje-ulje-divlje-ruze-za-oziljke-od-akni.json', oil: 'rosehip-oil', concern: 'acne-scars' },
{ file: 'najbolje-jojoba-ulje-za-akne.json', oil: 'jojoba-oil', concern: 'acne' },
{ file: 'najbolje-jojoba-ulje-za-masnu-kozu.json', oil: 'jojoba-oil', concern: 'oily-skin' },
{ file: 'najbolje-ulje-pasjeg-trna-za-hiperpigmentaciju.json', oil: 'sea-buckthorn-oil', concern: 'hyperpigmentation' },
{ file: 'najbolje-ulje-slatkog-badema-za-osetljivu-kozu.json', oil: 'sweet-almond-oil', concern: 'sensitive-skin' }
];
function extractContent(oldData) {
return {
schema: {
version: "1.0.0",
type: "oil-for-concern",
oilId: oldData.oilSlug,
concernId: oldData.concernSlug
},
content: {
whyThisWorks: oldData.whyThisWorks,
keyBenefits: oldData.keyBenefits,
howToApply: oldData.howToApply,
expectedResults: oldData.expectedResults,
timeframe: oldData.timeframe
},
metadata: {
productsToShow: oldData.productsToShow || [],
complementaryIngredients: oldData.complementaryIngredients || [],
customerResults: (oldData.customerResults || []).map(r => ({
quote: r.quote,
name: r.name,
age: r.age,
skinType: r.skinType,
timeframe: r.timeframe
})),
faqs: (oldData.faqs || []).map(f => ({
question: f.question,
answer: f.answer
})),
seoKeywords: oldData.seoKeywords || {},
relatedPages: oldData.relatedPages || {
otherOilsForSameConcern: [],
sameOilForOtherConcerns: []
}
}
};
}
function migrateFiles() {
const sourceDir = path.join(__dirname, '../data/oil-for-concern');
const targetDir = path.join(__dirname, '../data/content/oil-for-concern');
if (!fs.existsSync(targetDir)) {
fs.mkdirSync(targetDir, { recursive: true });
}
let migrated = 0;
let errors = [];
for (const mapping of legacyFiles) {
const sourcePath = path.join(sourceDir, mapping.file);
const targetFilename = `${mapping.oil}-${mapping.concern}.json`;
const targetPath = path.join(targetDir, targetFilename);
if (!fs.existsSync(sourcePath)) {
errors.push(`Source file not found: ${mapping.file}`);
continue;
}
try {
const oldData = JSON.parse(fs.readFileSync(sourcePath, 'utf8'));
const newData = extractContent(oldData);
fs.writeFileSync(targetPath, JSON.stringify(newData, null, 2));
console.log(`✓ Migrated: ${mapping.file}${targetFilename}`);
migrated++;
} catch (err) {
errors.push(`Error migrating ${mapping.file}: ${err.message}`);
}
}
console.log(`\n=== MIGRATION COMPLETE ===`);
console.log(`Migrated: ${migrated}/${legacyFiles.length} files`);
if (errors.length > 0) {
console.log(`\nErrors (${errors.length}):`);
errors.forEach(e => console.log(` - ${e}`));
}
}
if (require.main === module) {
migrateFiles();
}
module.exports = { extractContent, migrateFiles };