website-htmx-rustelo-code/scripts/migrations/migrate-content-slugs.sh

236 lines
8 KiB
Bash
Raw Normal View History

2026-07-10 03:44:13 +01:00
#!/bin/bash
# Content Migration Script - Normalize Categories, Tags, and Add Slugs
# This script normalizes all content to use proper URL-safe slugs
set -e
CONTENT_ROOT="content"
BACKUP_DIR="content-backup-$(date +%Y%m%d_%H%M%S)"
echo "🔄 Starting content migration to normalize categories, tags, and add slugs"
echo "📁 Content root: $CONTENT_ROOT"
echo "💾 Backup will be created at: $BACKUP_DIR"
# Create backup
echo "📦 Creating backup..."
cp -r "$CONTENT_ROOT" "$BACKUP_DIR"
echo "✅ Backup created successfully"
# Function to normalize text to slug format
normalize_slug() {
local text="$1"
echo "$text" | \
sed 's/[áàäâãå]/a/g; s/[éèëê]/e/g; s/[íìïî]/i/g; s/[óòöôõ]/o/g; s/[úùüû]/u/g; s/ç/c/g; s/ñ/n/g' | \
sed 's/[ÁÀÄÂÃÅ]/A/g; s/[ÉÈËÊ]/E/g; s/[ÍÌÏÎ]/I/g; s/[ÓÒÖÔÕ]/O/g; s/[ÚÙÜÛ]/U/g; s/Ç/C/g; s/Ñ/N/g' | \
tr '[:upper:]' '[:lower:]' | \
sed 's/[^a-z0-9]/-/g' | \
sed 's/--*/-/g' | \
sed 's/^-\|-$//g'
}
# Function to update markdown file frontmatter
update_markdown_file() {
local file="$1"
echo "🔄 Processing: $file"
# Create temporary files
local temp_file=$(mktemp)
local frontmatter_file=$(mktemp)
local content_file=$(mktemp)
# Extract frontmatter and content
awk '
BEGIN { in_frontmatter = 0; frontmatter_count = 0 }
/^---$/ {
frontmatter_count++;
if (frontmatter_count <= 2) {
in_frontmatter = (frontmatter_count == 1) ? 1 : 0;
if (frontmatter_count == 1) print > "'$frontmatter_file'";
if (frontmatter_count == 2) print > "'$frontmatter_file'";
} else {
print > "'$content_file'";
}
next;
}
in_frontmatter { print > "'$frontmatter_file'" }
!in_frontmatter && frontmatter_count >= 2 { print > "'$content_file'" }
' "$file"
# Process frontmatter
local updated_frontmatter=$(mktemp)
echo "---" > "$updated_frontmatter"
while IFS= read -r line; do
if [[ "$line" =~ ^---$ ]]; then
continue
elif [[ "$line" =~ ^category:\ *\"?([^\"]+)\"?$ ]]; then
local category="${BASH_REMATCH[1]}"
local normalized_category=$(normalize_slug "$category")
echo "category: \"$normalized_category\"" >> "$updated_frontmatter"
echo " 📝 Category: '$category' → '$normalized_category'"
elif [[ "$line" =~ ^tags:\ *\[(.*)\]$ ]]; then
local tags_content="${BASH_REMATCH[1]}"
# Parse tags and normalize them
local normalized_tags=""
IFS=',' read -ra TAG_ARRAY <<< "$tags_content"
for tag in "${TAG_ARRAY[@]}"; do
# Remove quotes and whitespace
tag=$(echo "$tag" | sed 's/["\[\]]//g' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
local normalized_tag=$(normalize_slug "$tag")
echo " 🏷️ Tag: '$tag' → '$normalized_tag'"
if [[ -n "$normalized_tags" ]]; then
normalized_tags="$normalized_tags, \"$normalized_tag\""
else
normalized_tags="\"$normalized_tag\""
fi
done
echo "tags: [$normalized_tags]" >> "$updated_frontmatter"
elif [[ "$line" =~ ^title:\ *\"?([^\"]+)\"?$ ]]; then
local title="${BASH_REMATCH[1]}"
echo "$line" >> "$updated_frontmatter"
# Add slug field if not present
if ! grep -q "^slug:" "$frontmatter_file"; then
local slug=$(normalize_slug "$title")
echo "slug: \"$slug\"" >> "$updated_frontmatter"
echo " 🔗 Added slug: '$slug'"
fi
else
echo "$line" >> "$updated_frontmatter"
fi
done < "$frontmatter_file"
echo "---" >> "$updated_frontmatter"
# Combine updated frontmatter with content
cat "$updated_frontmatter" > "$temp_file"
cat "$content_file" >> "$temp_file"
# Replace original file
mv "$temp_file" "$file"
# Cleanup
rm -f "$frontmatter_file" "$content_file" "$updated_frontmatter"
echo "✅ Updated: $file"
}
# Function to update JSON index files
update_json_index() {
local file="$1"
echo "🔄 Processing JSON index: $file"
# Create a temporary script to process the JSON
local temp_script=$(mktemp)
cat > "$temp_script" << 'EOF'
import json
import sys
import re
import unicodedata
def normalize_slug(text):
"""Normalize text to URL-safe slug format using proper Unicode normalization"""
# Normalize to NFD (decomposed form) and remove combining characters (accents)
normalized = unicodedata.normalize('NFD', text)
no_accents = ''.join(c for c in normalized if not unicodedata.combining(c))
# Convert to lowercase, replace non-alphanumeric with dashes, collapse dashes
slug = re.sub(r'[^a-zA-Z0-9]+', '-', no_accents.lower())
slug = re.sub(r'-+', '-', slug) # Collapse multiple dashes
slug = slug.strip('-') # Remove leading/trailing dashes
return slug
def update_content_item(item):
"""Update a single content item (blog post or prescription)"""
updated = False
# Normalize category
if 'category' in item and item['category']:
old_category = item['category']
new_category = normalize_slug(old_category)
if old_category != new_category:
item['category'] = new_category
print(f" 📝 Category: '{old_category}' → '{new_category}'")
updated = True
# Normalize tags
if 'tags' in item and isinstance(item['tags'], list):
old_tags = item['tags'][:]
new_tags = []
for tag in old_tags:
new_tag = normalize_slug(tag)
new_tags.append(new_tag)
if tag != new_tag:
print(f" 🏷️ Tag: '{tag}' → '{new_tag}'")
updated = True
item['tags'] = new_tags
# Add localized_slug if not present
if 'localized_slug' not in item and 'title' in item:
slug = normalize_slug(item['title'])
item['localized_slug'] = slug
print(f" 🔗 Added localized_slug: '{slug}'")
updated = True
return updated
# Read and process JSON file
with open(sys.argv[1], 'r', encoding='utf-8') as f:
data = json.load(f)
updated_any = False
# Process blog posts
if 'blog_posts' in data:
for post in data['blog_posts']:
if update_content_item(post):
updated_any = True
# Process prescriptions
if 'prescriptions' in data:
for prescription in data['prescriptions']:
if update_content_item(prescription):
updated_any = True
# Write back to file if updated
if updated_any:
with open(sys.argv[1], 'w', encoding='utf-8') as f:
json.dump(data, f, indent=2, ensure_ascii=False)
f.write('\n') # Add trailing newline
EOF
python3 "$temp_script" "$file"
rm -f "$temp_script"
echo "✅ Updated: $file"
}
# Process all markdown files
echo "🔍 Finding and processing markdown files..."
find "$CONTENT_ROOT" -name "*.md" -type f | while read -r file; do
update_markdown_file "$file"
done
# Process all JSON index files
echo "🔍 Finding and processing JSON index files..."
find "$CONTENT_ROOT" -name "index.json" -type f | while read -r file; do
update_json_index "$file"
done
echo ""
echo "✅ Content migration completed successfully!"
echo "📁 Backup location: $BACKUP_DIR"
echo ""
echo "📋 Summary of changes:"
echo " • Normalized all category names to lowercase with dashes"
echo " • Normalized all tag names to lowercase with dashes"
echo " • Added slug fields to markdown frontmatter"
echo " • Added localized_slug fields to JSON index files"
echo " • Removed accents and special characters from all slugs"
echo ""
echo "🔧 Next steps:"
echo " 1. Review the changes"
echo " 2. Test the application"
echo " 3. Update any hardcoded category/tag references"
echo " 4. If satisfied, remove the backup: rm -rf $BACKUP_DIR"