Add full SEO optimization for Spanglish social and language events

- Add comprehensive metadata to root layout with Open Graph, Twitter cards
- Create dynamic sitemap.ts for all pages and events
- Create robots.ts with proper allow/disallow rules
- Add JSON-LD Event structured data to event detail pages
- Add page-specific metadata to events, community, contact, FAQ pages
- Add FAQ structured data schema
- Update footer with local SEO text for Asunción, Paraguay
- Add web manifest for mobile SEO
- Create 404 page with proper noindex
- Optimize image alt text and add lazy loading
- Add NEXT_PUBLIC_SITE_URL env variable
- Add about/ folder to gitignore
This commit is contained in:
root
2026-01-30 21:05:25 +00:00
parent d0ea55dc5b
commit 47ba754f05
40 changed files with 2659 additions and 420 deletions

View File

@@ -0,0 +1,91 @@
import { MetadataRoute } from 'next';
const siteUrl = process.env.NEXT_PUBLIC_SITE_URL || 'https://spanglish.com.py';
const apiUrl = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001';
interface Event {
id: string;
status: string;
updatedAt: string;
}
async function getPublishedEvents(): Promise<Event[]> {
try {
const response = await fetch(`${apiUrl}/api/events?status=published`, {
next: { revalidate: 3600 }, // Cache for 1 hour
});
if (!response.ok) return [];
const data = await response.json();
return data.events || [];
} catch {
return [];
}
}
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
// Fetch published events for dynamic event pages
const events = await getPublishedEvents();
// Static pages
const staticPages: MetadataRoute.Sitemap = [
{
url: siteUrl,
lastModified: new Date(),
changeFrequency: 'weekly',
priority: 1,
},
{
url: `${siteUrl}/events`,
lastModified: new Date(),
changeFrequency: 'daily',
priority: 0.9,
},
{
url: `${siteUrl}/community`,
lastModified: new Date(),
changeFrequency: 'monthly',
priority: 0.7,
},
{
url: `${siteUrl}/contact`,
lastModified: new Date(),
changeFrequency: 'monthly',
priority: 0.6,
},
{
url: `${siteUrl}/faq`,
lastModified: new Date(),
changeFrequency: 'monthly',
priority: 0.6,
},
// Legal pages
{
url: `${siteUrl}/legal/terms-policy`,
lastModified: new Date(),
changeFrequency: 'yearly',
priority: 0.3,
},
{
url: `${siteUrl}/legal/privacy-policy`,
lastModified: new Date(),
changeFrequency: 'yearly',
priority: 0.3,
},
{
url: `${siteUrl}/legal/refund-cancelation-policy`,
lastModified: new Date(),
changeFrequency: 'yearly',
priority: 0.3,
},
];
// Dynamic event pages
const eventPages: MetadataRoute.Sitemap = events.map((event) => ({
url: `${siteUrl}/events/${event.id}`,
lastModified: new Date(event.updatedAt),
changeFrequency: 'weekly' as const,
priority: 0.8,
}));
return [...staticPages, ...eventPages];
}