| Server IP : 3.147.158.171 / Your IP : 216.73.216.229 Web Server : Apache/2.4.67 (Amazon Linux) OpenSSL/3.5.5 System : Linux ip-172-31-2-178.us-east-2.compute.internal 6.1.172-216.329.amzn2023.x86_64 #1 SMP PREEMPT_DYNAMIC Wed May 20 06:31:34 UTC 2026 x86_64 User : ec2-user ( 1000) PHP Version : 8.4.21 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : OFF Directory : /tsai/repo/builder/backend/scripts/ |
Upload File : |
#!/usr/bin/env python3
"""
Register Favicons as WordPress Site Icons
Scans existing WordPress sites for favicon.svg files, generates PNG versions,
and registers them as WordPress Site Icons via WP-CLI.
Intended as a one-time backfill for sites created before the builder
automatically registered favicons.
Usage:
python register_favicons.py --sites-dir /data/tsai/sites --prefix scike-
python register_favicons.py --sites-dir /data/tsai/sites --prefix scike- --dry-run
"""
from __future__ import annotations
import argparse
import re
import subprocess
import sys
from pathlib import Path
# Add parent scripts dir so we can import generate_favicon
sys.path.insert(0, str(Path(__file__).resolve().parent))
from generate_favicon import generate_png
def parse_svg(svg_path: Path) -> dict | None:
"""Extract character, background color, and foreground color from an SVG favicon."""
text = svg_path.read_text()
bg_match = re.search(r'<rect[^>]+fill="([^"]+)"', text)
fg_match = re.search(r'<text[^>]+fill="([^"]+)"[^>]*>([^<]+)</text>', text)
if not bg_match or not fg_match:
return None
return {
'bg': bg_match.group(1),
'fg': fg_match.group(1),
'char': fg_match.group(2),
}
def wp_cli(args: list[str], wp_path: str) -> subprocess.CompletedProcess:
"""Run a WP-CLI command for a given site path."""
cmd = ['wp'] + args + [f'--path={wp_path}']
return subprocess.run(cmd, capture_output=True, text=True)
def register_site(site_dir: Path, dry_run: bool = False) -> bool:
"""Generate PNG and register as WordPress Site Icon for one site."""
svg_path = site_dir / 'favicon.svg'
png_path = site_dir / 'favicon.png'
if not svg_path.exists():
print(f" No favicon.svg found, skipping")
return False
params = parse_svg(svg_path)
if not params:
print(f" Could not parse favicon.svg, skipping")
return False
print(f" Parsed: char='{params['char']}' bg={params['bg']} fg={params['fg']}")
if dry_run:
print(f" [dry-run] Would generate PNG and register as site icon")
return True
# Generate PNG
generate_png(params['char'], params['bg'], params['fg'], png_path)
print(f" Generated {png_path}")
# Import into WordPress media library
result = wp_cli(['media', 'import', str(png_path), '--title=Site Icon', '--porcelain'], str(site_dir))
if result.returncode != 0:
print(f" Failed to import media: {result.stderr.strip()}")
return False
icon_id = result.stdout.strip()
print(f" Imported as attachment {icon_id}")
# Set as site icon
result = wp_cli(['option', 'update', 'site_icon', icon_id], str(site_dir))
if result.returncode != 0:
print(f" Failed to set site_icon: {result.stderr.strip()}")
return False
print(f" Registered as site icon")
return True
def main():
parser = argparse.ArgumentParser(description='Register favicons as WordPress Site Icons')
parser.add_argument('--sites-dir', required=True, help='Parent directory containing site directories')
parser.add_argument('--prefix', default='', help='Only process directories matching this prefix (e.g., "scike-")')
parser.add_argument('--dry-run', action='store_true', help='Show what would be done without making changes')
args = parser.parse_args()
sites_dir = Path(args.sites_dir)
if not sites_dir.is_dir():
print(f"Error: {sites_dir} is not a directory")
sys.exit(1)
# Find site directories
site_dirs = sorted(
d for d in sites_dir.iterdir()
if d.is_dir() and d.name.startswith(args.prefix)
)
if not site_dirs:
print(f"No site directories found in {sites_dir} with prefix '{args.prefix}'")
sys.exit(0)
print(f"Found {len(site_dirs)} site directories")
if args.dry_run:
print("[DRY RUN MODE]")
print()
success = 0
skipped = 0
for site_dir in site_dirs:
print(f"{site_dir.name}:")
if register_site(site_dir, dry_run=args.dry_run):
success += 1
else:
skipped += 1
print(f"\nDone. Registered: {success}, Skipped: {skipped}")
if __name__ == '__main__':
main()