Introducción
Este tutorial explica con todo lujo de detalles cómo diseñar y construir un layout de blog tipo “tarjeta destacada grid” en WordPress. El objetivo es crear una portada donde aparezca una tarjeta grande y llamativa con el artículo destacado en la parte superior y, debajo, una cuadrícula responsiva con el resto de las entradas. Incluye: PHP para la plantilla, CSS moderno (CSS Grid y Flexbox), optimización de imágenes, accesibilidad y buenas prácticas de rendimiento.
Requisitos y decisiones de diseño
- WordPress: Tema hijo (child theme) sobre un tema base o tema personalizado para editar plantillas con seguridad.
- Método para identificar el destacado: se puede usar post meta (campo personalizado), categoría/tag “featured”, o un sticky post. En los ejemplos usaré un meta booleano is_featured para mayor control.
- Responsive: usar CSS Grid para la cuadrícula y una tarjeta destacada que ocupe todo el ancho en móvil y esté centrada en pantallas grandes.
- Optimización: tamaños de imagen registrados en functions.php, lazy-loading con native loading=lazy y fallback con IntersectionObserver.
Arquitectura de ficheros sugerida
- functions.php — registrar tamaños, enqueue de estilos/scripts y helper para query del destacado.
- template-parts/content-featured.php — plantilla de la tarjeta destacada.
- template-parts/content-grid-item.php — plantilla de un ítem del grid.
- front-page.php o home.php — plantilla principal que monta el layout.
- assets/css/home-layout.css — estilos para este layout.
- assets/js/lazyload.js — optional: fallback lazy load.
1) Registrar tamaños de imagen y assets (functions.php)
Registrar tamaños ayuda a servir imágenes adaptadas y mejorar Core Web Vitals.
// functions.php (añadir en tu child theme)
add_action(after_setup_theme, function() {
// tamaño para la tarjeta destacada: ancho grande, altura controlada con crop centrado
add_image_size(featured-large, 1400, 700, true)
// item grid: cuadrado o rectangular
add_image_size(grid-medium, 600, 400, true)
// thumbnail pequeño
add_image_size(grid-small, 400, 260, true)
})
add_action(wp_enqueue_scripts, function() {
wp_enqueue_style(home-layout, get_stylesheet_directory_uri() . /assets/css/home-layout.css, array(), 1.0)
wp_enqueue_script(home-lazy, get_stylesheet_directory_uri() . /assets/js/lazyload.js, array(), 1.0, true)
})
2) Marcar un post como destacado
Se puede usar un campo personalizado booleano llamado is_featured. Puedes añadirlo manualmente o con ACF (Advanced Custom Fields). En el ejemplo usaremos meta_key = is_featured con valor 1.
3) Query: conseguir el post destacado y los demás (front-page.php)
Crear dos consultas: una para el post destacado (1) y otra para los posts del grid excluyendo el destacado para evitar duplicados.
// front-page.php (fragmento principal)
post,
posts_per_page => 1,
meta_key => is_featured,
meta_value => 1,
ignore_sticky_posts => true,
)
featured_query = new WP_Query(featured_args)
if ( featured_query->have_posts() ) :
while ( featured_query->have_posts() ) : featured_query->the_post()
// template part para la tarjeta destacada
get_template_part(template-parts/content, featured)
endwhile
wp_reset_postdata()
endif
// 2) obtener posts para el grid, excluyendo el ID del destacado
exclude_ids = array()
if ( ! empty( featured_query->posts ) ) {
foreach ( featured_query->posts as f ) {
exclude_ids[] = f->ID
}
}
grid_args = array(
post_type => post,
posts_per_page => 9,
post__not_in => exclude_ids,
paged => get_query_var(paged) ? get_query_var(paged) : 1,
)
grid_query = new WP_Query(grid_args)
if ( grid_query->have_posts() ) :
echo ltdiv class=home-gridgt // el markup real está en CSS/templating
while ( grid_query->have_posts() ) : grid_query->the_post()
get_template_part(template-parts/content, grid-item)
endwhile
echo lt/divgt
// navegación de paginación aquí si hace falta
wp_reset_postdata()
endif
?>
4) Plantilla de la tarjeta destacada (template-parts/content-featured.php)
El HTML debe ser semántico y accesible. Mostrar imagen destacada con srcset, título, excerpt y enlace.
// template-parts/content-featured.phplta href=lt?php the_permalink() ?gt class=featured-link aria-label=Leer: lt?php the_title_attribute() ?gtgt lt?php if ( has_post_thumbnail() ) { // usar el tamaño registrado featured-large y srcset por defecto the_post_thumbnail(featured-large, array(class => featured-img, loading => lazy, alt => get_the_title())) } else { // fallback: placeholder echo ltimg src= . esc_url(get_stylesheet_directory_uri() . /assets/img/placeholder-wide.jpg) . class=featured-img loading=lazy alt= /gt } ?gt ltdiv class=featured-contentgt lth2 id=featured-title class=featured-titlegtlt?php the_title() ?gtlt/h2gt ltdiv class=featured-excerptgtlt?php echo wp_trim_words(get_the_excerpt(), 28) ?gtlt/divgt lt/divgt lt/agt
5) Plantilla de un ítem del grid (template-parts/content-grid-item.php)
// template-parts/content-grid-item.phplta href=lt?php the_permalink() ?gt class=grid-link aria-label=Leer: lt?php the_title_attribute() ?gtgt ltdiv class=grid-mediagt lt?php if ( has_post_thumbnail() ) { the_post_thumbnail(grid-medium, array(class => grid-img, loading => lazy, alt => get_the_title())) } else { echo ltimg src= . esc_url(get_stylesheet_directory_uri() . /assets/img/placeholder-rect.jpg) . class=grid-img loading=lazy alt= /gt } ?gt lt/divgt ltdiv class=grid-bodygt lth3 class=grid-titlegtlt?php the_title() ?gtlt/h3gt ltdiv class=grid-metagtlt?php echo get_the_date() ?gtlt/divgt lt/divgt lt/agt
6) CSS: estructura responsive y estilos (assets/css/home-layout.css)
Usamos CSS Grid para la cuadrícula y Flexbox para el contenido interno. La tarjeta destacada se presenta arriba, ocupando todo el ancho en móvil y en pantalla grande puede tener padding y un max-width.
/ assets/css/home-layout.css /
/ Reset breve para los componentes usados /
.featured-card, .home-grid, .grid-item { box-sizing: border-box }
/ Contenedor principal: se puede envolver con .site-main en tu tema /
.featured-card {
display: block
margin: 0 auto 2rem
max-width: 1400px
overflow: hidden
border-radius: 8px
background: #fff
box-shadow: 0 6px 24px rgba(0,0,0,0.08)
}
.featured-link {
display: grid
grid-template-columns: 1fr
text-decoration: none
color: inherit
}
/ imagen de la featured /
.featured-img {
width: 100%
height: auto
display: block
object-fit: cover
aspect-ratio: 16/9 / moderno y útil /
}
/ contenido superpuesto o debajo según diseño: aquí simple debajo /
.featured-content {
padding: 1.25rem
}
.featured-title {
margin: 0 0 .5rem
font-size: 1.75rem
line-height: 1.1
}
.featured-excerpt { color: #444 }
/ Grid principal /
.home-grid {
display: grid
grid-template-columns: repeat(1, 1fr)
gap: 1rem
max-width: 1400px
margin: 0 auto
padding: 0 1rem 3rem
}
/ ítem del grid /
.grid-item {
background: #fff
border-radius: 6px
overflow: hidden
box-shadow: 0 4px 14px rgba(0,0,0,0.06)
}
.grid-link {
color: inherit
text-decoration: none
display: flex
flex-direction: column
height: 100%
}
.grid-media { width: 100% }
.grid-img {
width: 100%
height: auto
display: block
object-fit: cover
aspect-ratio: 3/2
}
/ cuerpo /
.grid-body {
padding: .75rem
}
.grid-title {
margin: 0 0 .5rem
font-size: 1.05rem
}
/ Responsive: tablet y desktop /
@media (min-width: 640px) {
.home-grid { grid-template-columns: repeat(2, 1fr) gap: 1.25rem }
.featured-link { grid-template-columns: 2fr 1fr } / si queremos imagen contenido side-by-side en tablet /
}
@media (min-width: 1024px) {
.home-grid { grid-template-columns: repeat(3, 1fr) gap: 1.5rem }
.featured-card { margin-bottom: 2.5rem }
.featured-title { font-size: 2rem }
}
7) Lazy-loading progresivo (fallback JS)
Los navegadores modernos soportan loading=lazy. Para mejorar compatibilidad o añadir animaciones, se puede usar IntersectionObserver como fallback.
// assets/js/lazyload.js
document.addEventListener(DOMContentLoaded, function() {
if (loading in HTMLImageElement.prototype) {
// los navegadores modernos ya manejan lazy nativo => nada que hacer
return
}
var lazyImages = [].slice.call(document.querySelectorAll(img[loading=lazy]))
if (IntersectionObserver in window) {
let lazyObserver = new IntersectionObserver(function(entries, observer) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
let img = entry.target
// si usamos data-src para src real
if (img.dataset.src) {
img.src = img.dataset.src
if (img.dataset.srcset) img.srcset = img.dataset.srcset
}
img.removeAttribute(loading)
lazyObserver.unobserve(img)
}
})
})
lazyImages.forEach(function(img) { lazyObserver.observe(img) })
} else {
// fallback simple: cargar inmediatamente
lazyImages.forEach(function(img) {
if (img.dataset.src) img.src = img.dataset.src
if (img.dataset.srcset) img.srcset = img.dataset.srcset
})
}
})
8) Accesibilidad y SEO
- Alt de imágenes: usa siempre alt útil. En the_post_thumbnail hemos pasado get_the_title() ajusta si necesitas descripciones más completas.
- Jerarquía de títulos: asegúrate de que no rompes la jerarquía H1/H2 del tema. Usa h2/h3 según corresponda.
- Enlaces: usa texto comprensible y atributos aria cuando sea necesario.
- Datos estructurados: asegurate de que tu tema sigue las plantillas de schema.org para artículos o usa plugins para añadir JSON-LD.
9) Rendimiento y buenas prácticas
- Registra tamaños de imagen pertinentes y usa srcset (WordPress lo gestiona con the_post_thumbnail).
- Evita queries innecesarias usa transients si la página es muy visitada y los posts destacados no cambian frecuentemente.
- Minifica CSS/JS y sirve archivos desde el theme o CDN.
- Si la portada muestra muchos posts, añade paginación o carga progresiva (infinite scroll) con cuidado en accesibilidad.
10) Variantes y mejoras posibles
- Tarjeta destacada con fondo oscuro y contenido superpuesto (usar position absolute recuerda accesibilidad y contraste).
- Grid tipo masonry: usar CSS Grid con dense-placement o librerías como Masonry/Isotope si se necesita un layout irregular.
- Usar bloques de Gutenberg o Block Patterns para crear el layout sin editar PHP (ideal si prefieres editor visual).
- Permitir que el editor marque el post destacado mediante ACF y un checkbox para simplificar al usuario.
Tabla de breakpoints sugeridos
| Breakpoint | Uso |
|---|---|
| 320px – 639px | Mobile: featured full width grid 1 columna |
| 640px – 1023px | Tablet: featured side-by-side opcional grid 2 columnas |
| 1024px | Desktop: grid 3 columnas o más featured con más espacio |
Resumen final
Con los pasos anteriores dispondrás de un layout limpio y optimizado de “tarjeta destacada grid”. La estrategia clave es: identificar claramente el post destacado (post meta), usar dos queries separadas para evitar duplicados, servir imágenes en tamaños adecuados y aplicar CSS Grid para una cuadrícula responsiva. Complementa con lazy-loading y buenas prácticas de accesibilidad y rendimiento.
Leave a Reply