Mejorar SEO: schema JSON-LD, robots.txt, sitemap y meta tags

- Agregar JSON-LD (Organization, WebSite, SoftwareApplication y FAQPage)
- Crear robots.txt y sitemap.xml con sitio de producción
- Completar meta tags: robots, theme-color, og:image:type y twitter:url
- Envolver preguntas del FAQ en h3
- Registrar filtro json para Nunjucks en Eleventy
This commit is contained in:
Jose Selesan
2026-09-21 14:05:13 -03:00
parent 657f465d82
commit 01e31ddbbd
6 changed files with 134 additions and 6 deletions

View File

@@ -13,6 +13,8 @@ export default function (eleventyConfig) {
return new Intl.NumberFormat(locale).format(value);
});
eleventyConfig.addFilter("json", (value) => JSON.stringify(value));
return {
dir: {
input: "src",

View File

@@ -5,6 +5,9 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{{ title or site.name }}</title>
<meta name="description" content="{{ description or site.description }}" />
<meta name="robots" content="index, follow" />
<meta name="theme-color" content="#1d33d8" media="(prefers-color-scheme: light)" />
<meta name="theme-color" content="#0b1023" media="(prefers-color-scheme: dark)" />
<link rel="canonical" href="{{ site.url }}/" />
<link rel="icon" type="image/svg+xml" href="/assets/favicon.svg" />
<link rel="icon" type="image/png" sizes="512x512" href="/assets/isotipo-y-organica-preview.png" />
@@ -17,6 +20,7 @@
<meta property="og:title" content="{{ title or site.name }}" />
<meta property="og:description" content="{{ description or site.description }}" />
<meta property="og:image" content="{{ site.url }}/assets/og-image.png" />
<meta property="og:image:type" content="image/png" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:image:alt" content="{{ site.name }}" />
@@ -27,6 +31,9 @@
<meta name="twitter:title" content="{{ title or site.name }}" />
<meta name="twitter:description" content="{{ description or site.description }}" />
<meta name="twitter:image" content="{{ site.url }}/assets/og-image.png" />
<meta name="twitter:url" content="{{ site.url }}/" />
{% include "partials/seo-schema.njk" %}
<script>
if (localStorage.getItem('theme') === 'dark' || (!localStorage.getItem('theme') && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
document.documentElement.classList.add('dark');

View File

@@ -10,7 +10,7 @@
<div class="mt-10 space-y-4">
<details class="group rounded-2xl border border-slate-200 bg-white p-6 shadow-sm open:shadow-md dark:border-slate-800 dark:bg-slate-900">
<summary class="flex cursor-pointer list-none items-center justify-between gap-4 text-base font-bold focus:outline-none focus-visible:ring-2 focus-visible:ring-brand-500 focus-visible:ring-offset-2 dark:focus-visible:ring-offset-slate-950 [&::-webkit-details-marker]:hidden">
¿Para quién es Gruperly?
<h3 class="text-base font-bold">¿Para quién es Gruperly?</h3>
<svg class="h-5 w-5 shrink-0 text-brand-500 transition-transform group-open:rotate-45" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 5v14M5 12h14" /></svg>
</summary>
<p class="mt-3 text-sm leading-relaxed text-slate-600 dark:text-slate-400">
@@ -20,7 +20,7 @@
<details class="group rounded-2xl border border-slate-200 bg-white p-6 shadow-sm open:shadow-md dark:border-slate-800 dark:bg-slate-900">
<summary class="flex cursor-pointer list-none items-center justify-between gap-4 text-base font-bold focus:outline-none focus-visible:ring-2 focus-visible:ring-brand-500 focus-visible:ring-offset-2 dark:focus-visible:ring-offset-slate-950 [&::-webkit-details-marker]:hidden">
¿Cómo creo mi primer grupo?
<h3 class="text-base font-bold">¿Cómo creo mi primer grupo?</h3>
<svg class="h-5 w-5 shrink-0 text-brand-500 transition-transform group-open:rotate-45" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 5v14M5 12h14" /></svg>
</summary>
<p class="mt-3 text-sm leading-relaxed text-slate-600 dark:text-slate-400">
@@ -30,7 +30,7 @@
<details class="group rounded-2xl border border-slate-200 bg-white p-6 shadow-sm open:shadow-md dark:border-slate-800 dark:bg-slate-900">
<summary class="flex cursor-pointer list-none items-center justify-between gap-4 text-base font-bold focus:outline-none focus-visible:ring-2 focus-visible:ring-brand-500 focus-visible:ring-offset-2 dark:focus-visible:ring-offset-slate-950 [&::-webkit-details-marker]:hidden">
¿Cómo incorporo participantes?
<h3 class="text-base font-bold">¿Cómo incorporo participantes?</h3>
<svg class="h-5 w-5 shrink-0 text-brand-500 transition-transform group-open:rotate-45" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 5v14M5 12h14" /></svg>
</summary>
<p class="mt-3 text-sm leading-relaxed text-slate-600 dark:text-slate-400">
@@ -40,7 +40,7 @@
<details class="group rounded-2xl border border-slate-200 bg-white p-6 shadow-sm open:shadow-md dark:border-slate-800 dark:bg-slate-900">
<summary class="flex cursor-pointer list-none items-center justify-between gap-4 text-base font-bold focus:outline-none focus-visible:ring-2 focus-visible:ring-brand-500 focus-visible:ring-offset-2 dark:focus-visible:ring-offset-slate-950 [&::-webkit-details-marker]:hidden">
¿Cómo se cobra a los participantes?
<h3 class="text-base font-bold">¿Cómo se cobra a los participantes?</h3>
<svg class="h-5 w-5 shrink-0 text-brand-500 transition-transform group-open:rotate-45" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 5v14M5 12h14" /></svg>
</summary>
<p class="mt-3 text-sm leading-relaxed text-slate-600 dark:text-slate-400">
@@ -50,7 +50,7 @@
<details class="group rounded-2xl border border-slate-200 bg-white p-6 shadow-sm open:shadow-md dark:border-slate-800 dark:bg-slate-900">
<summary class="flex cursor-pointer list-none items-center justify-between gap-4 text-base font-bold focus:outline-none focus-visible:ring-2 focus-visible:ring-brand-500 focus-visible:ring-offset-2 dark:focus-visible:ring-offset-slate-950 [&::-webkit-details-marker]:hidden">
¿Qué diferencia hay entre actividades recurrentes y eventos especiales?
<h3 class="text-base font-bold">¿Qué diferencia hay entre actividades recurrentes y eventos especiales?</h3>
<svg class="h-5 w-5 shrink-0 text-brand-500 transition-transform group-open:rotate-45" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 5v14M5 12h14" /></svg>
</summary>
<p class="mt-3 text-sm leading-relaxed text-slate-600 dark:text-slate-400">
@@ -60,7 +60,7 @@
<details class="group rounded-2xl border border-slate-200 bg-white p-6 shadow-sm open:shadow-md dark:border-slate-800 dark:bg-slate-900">
<summary class="flex cursor-pointer list-none items-center justify-between gap-4 text-base font-bold focus:outline-none focus-visible:ring-2 focus-visible:ring-brand-500 focus-visible:ring-offset-2 dark:focus-visible:ring-offset-slate-950 [&::-webkit-details-marker]:hidden">
¿Necesito una cuenta para usar Gruperly?
<h3 class="text-base font-bold">¿Necesito una cuenta para usar Gruperly?</h3>
<svg class="h-5 w-5 shrink-0 text-brand-500 transition-transform group-open:rotate-45" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 5v14M5 12h14" /></svg>
</summary>
<p class="mt-3 text-sm leading-relaxed text-slate-600 dark:text-slate-400">

View File

@@ -0,0 +1,101 @@
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@graph": [
{
"@type": "Organization",
"@id": "{{ site.url }}/#organization",
"name": "{{ site.name }}",
"url": "{{ site.url }}/",
"logo": {
"@type": "ImageObject",
"url": "{{ site.url }}/assets/logotipo-y-organica.svg"
},
"sameAs": []
},
{
"@type": "WebSite",
"@id": "{{ site.url }}/#website",
"url": "{{ site.url }}/",
"name": "{{ site.name }}",
"publisher": { "@id": "{{ site.url }}/#organization" },
"inLanguage": "es-AR"
},
{
"@type": "SoftwareApplication",
"@id": "{{ site.url }}/#software",
"name": "{{ site.name }}",
"applicationCategory": "BusinessApplication",
"operatingSystem": "Web",
"url": "{{ site.url }}/",
"description": {{ (description or site.description) | json | safe }},
"inLanguage": "es-AR",
"offers": [
{% for plan in pricing.plans %}
{
"@type": "Offer",
"name": "{{ plan.name }}",
"price": "{{ plan.price.usd }}",
"priceCurrency": "USD",
"description": {{ plan.tagline | json | safe }}
}{% if not loop.last %},{% endif %}
{% endfor %}
]
},
{
"@type": "FAQPage",
"@id": "{{ site.url }}/#faq",
"mainEntity": [
{
"@type": "Question",
"name": "¿Para quién es Gruperly?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Para profesionales que trabajan con grupos de personas: profesores, personal trainers, instructores y perfiles similares que necesitan organizar grupos, participantes y cobros."
}
},
{
"@type": "Question",
"name": "¿Cómo creo mi primer grupo?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Creás tu cuenta y definís el nombre del grupo, los días y el horario de las clases, el cupo máximo, el precio y el tipo de cobro (mensual o por clase). Después siempre podés editarlo."
}
},
{
"@type": "Question",
"name": "¿Cómo incorporo participantes?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Registrás a cada participante en el grupo donde participa con sus datos de contacto. Gruperly guarda esa información y sus cobros por grupo."
}
},
{
"@type": "Question",
"name": "¿Cómo se cobra a los participantes?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Por grupo definís un precio, un tipo de cobro (mensual o por clase) y un día de vencimiento. Cada cobro queda con un estado claro: al día, pendiente o atrasado."
}
},
{
"@type": "Question",
"name": "¿Qué diferencia hay entre actividades recurrentes y eventos especiales?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Las actividades recurrentes son las clases habituales de un grupo, con días y horarios repetidos. Los eventos especiales son workshops, talleres o encuentros puntuales, separados de las clases recurrentes."
}
},
{
"@type": "Question",
"name": "¿Necesito una cuenta para usar Gruperly?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Sí. Creás una cuenta con tu nombre, email y contraseña, y confirmás tu email desde el enlace de verificación."
}
}
]
}
]
}
</script>

7
src/robots.txt.njk Normal file
View File

@@ -0,0 +1,7 @@
---
permalink: /robots.txt
---
User-agent: *
Allow: /
Sitemap: {{ site.url }}/sitemap.xml

11
src/sitemap.xml.njk Normal file
View File

@@ -0,0 +1,11 @@
---
permalink: /sitemap.xml
---
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>{{ site.url }}/</loc>
<changefreq>monthly</changefreq>
<priority>1.0</priority>
</url>
</urlset>