WordPress nació como plataforma de blogs, pero hace mucho que dejó de ser solo eso: hoy gestiona porfolios, inmobiliarias, academias, directorios de empresas y tiendas enteras. La pieza que hace posible esa versatilidad son los custom post types de WordPress: tipos de contenido personalizados que conviven con las entradas y las páginas, pero con su propio nombre, sus propios campos, sus propias URLs y su propio apartado en el escritorio. Si alguna vez has intentado gestionar «proyectos», «recetas» o «cursos» a base de entradas normales y categorías, sabes lo rápido que se convierte en un caos. En esta guía completa aprenderás qué es exactamente un Custom Post Type (CPT), cuándo tiene sentido crearlo y cuándo no, cómo registrarlo con código PHP completo y correcto, cómo añadirle taxonomías propias, cómo mostrarlo en tu tema y qué implicaciones tiene para el SEO. Al terminar podrás estructurar cualquier proyecto con la solidez de un desarrollador profesional.
Qué son los custom post types de WordPress
En WordPress, todo contenido es técnicamente un «post»: las entradas del blog (post), las páginas (page), los adjuntos de la mediateca (attachment), las revisiones o los menús de navegación. Todos se guardan en la misma tabla de la base de datos (wp_posts) y se distinguen por el valor de la columna post_type. Un custom post type no es más que un nuevo valor en esa columna, registrado por ti, con sus propias reglas: qué características admite (editor, imagen destacada, extracto), cómo se llama en el menú, qué URL tienen sus elementos y si aparece o no en los resultados de búsqueda.
Ejemplos clásicos donde los custom post types de WordPress brillan:
- Porfolio: proyectos con imagen, cliente y tecnología usada.
- Inmobiliaria: propiedades con precio, superficie y ubicación.
- Academia: cursos y lecciones con duración y nivel.
- Restaurante: platos con alérgenos y precio.
- Eventos: con fecha, lugar y aforo.
De hecho, ya los usas sin saberlo: los productos de WooCommerce son un CPT llamado product, y los formularios de casi cualquier plugin también se guardan como tipos de contenido propios.
Cuándo crear un CPT (y cuándo no)
La pregunta clave: ¿este contenido es conceptualmente distinto de una entrada de blog? Si la respuesta es sí (tiene sentido listarlo por separado, con sus propios archivos y su propia estructura), es candidato a CPT. Si solo quieres agrupar entradas por temática, la herramienta correcta son las categorías y etiquetas de toda la vida.
| Situación | Solución adecuada |
|---|---|
| Separar el blog por temáticas | Categorías |
| Fichas de productos, cursos, inmuebles… | Custom Post Type |
| Marcar entradas con palabras clave sueltas | Etiquetas |
| Clasificar un CPT (género de un libro, zona de un inmueble) | Taxonomía personalizada |
| Datos concretos de cada elemento (precio, fecha, ISBN) | Campos personalizados (post meta) |
Otra decisión previa: ¿código o plugin? Plugins como Custom Post Type UI o Pods permiten registrar CPT desde el panel sin escribir PHP, y son perfectamente válidos. A cambio, generan dependencia: si el plugin se desactiva, el contenido no se borra pero desaparece del escritorio. El registro por código, que veremos ahora, es más ligero, portable y controlable, y es como lo hacen todos los temas y plugins profesionales.
Cómo registrar un custom post type con código
Todo gira en torno a una función: register_post_type(), que debe ejecutarse en el hook init. Este es un registro completo y comentado para un CPT de porfolio, listo para usar:
<?php
function biblioweb_registrar_cpt_proyecto() {
$labels = array(
'name' => 'Proyectos',
'singular_name' => 'Proyecto',
'menu_name' => 'Porfolio',
'add_new' => 'Añadir nuevo',
'add_new_item' => 'Añadir nuevo proyecto',
'edit_item' => 'Editar proyecto',
'new_item' => 'Nuevo proyecto',
'view_item' => 'Ver proyecto',
'search_items' => 'Buscar proyectos',
'not_found' => 'No se han encontrado proyectos',
'not_found_in_trash' => 'No hay proyectos en la papelera',
'all_items' => 'Todos los proyectos',
);
$args = array(
'labels' => $labels,
'public' => true,
'has_archive' => true,
'menu_position'=> 20,
'menu_icon' => 'dashicons-portfolio',
'rewrite' => array( 'slug' => 'proyectos', 'with_front' => false ),
'supports' => array( 'title', 'editor', 'thumbnail', 'excerpt', 'revisions', 'custom-fields' ),
'show_in_rest' => true, // Necesario para el editor de bloques y la REST API.
'taxonomies' => array(),
);
register_post_type( 'proyecto', $args );
}
add_action( 'init', 'biblioweb_registrar_cpt_proyecto' );
Repasemos los argumentos que más dudas generan:
public: entrue, el CPT tiene URLs propias, aparece en el escritorio y es visible. Para contenido interno (por ejemplo, testimonios que solo se muestran incrustados) se puede afinar conpublicly_queryableyexclude_from_search.has_archive: crea la página de archivo entudominio.com/proyectos/con el listado de todos los elementos.rewrite: define el slug de las URLs.with_front => falseevita heredar prefijos de la estructura de enlaces permanentes (como/blog/).supports: qué cajas aparecen en el editor. Si tu CPT no necesita editor de texto, quítalo y el formulario quedará más limpio.show_in_rest: imprescindible entruesi quieres usar Gutenberg con este CPT o consumirlo desde la REST API.menu_icon: cualquier icono de la librería Dashicons, o la ruta a un SVG propio.
Un aviso crítico: tras registrar o modificar un CPT, visita Ajustes → Enlaces permanentes y pulsa «Guardar cambios». Ese gesto regenera las reglas de reescritura; si no lo haces, las URLs nuevas devolverán un error 404 y perderás un buen rato buscando un fallo que no está en tu código.
¿Dónde colocarlo? En un plugin propio o en un gestor de snippets como WPCode, que analizamos a fondo aquí. Evita el functions.php del tema: un CPT es funcionalidad, no diseño, y debe sobrevivir a un cambio de tema.
Taxonomías personalizadas: clasificar tu nuevo contenido
Las categorías y etiquetas estándar pertenecen a las entradas. Para clasificar un CPT lo correcto es registrar taxonomías propias con register_taxonomy(). Siguiendo con el porfolio, creemos una taxonomía «Tipo de proyecto»:
<?php
function biblioweb_registrar_taxonomia_tipo() {
$labels = array(
'name' => 'Tipos de proyecto',
'singular_name' => 'Tipo de proyecto',
'search_items' => 'Buscar tipos',
'all_items' => 'Todos los tipos',
'edit_item' => 'Editar tipo',
'add_new_item' => 'Añadir nuevo tipo',
);
register_taxonomy(
'tipo_proyecto',
array( 'proyecto' ),
array(
'labels' => $labels,
'hierarchical' => true, // true = como categorías; false = como etiquetas.
'rewrite' => array( 'slug' => 'tipo-proyecto' ),
'show_in_rest' => true,
)
);
}
add_action( 'init', 'biblioweb_registrar_taxonomia_tipo' );
El parámetro hierarchical decide el comportamiento: en true funciona como las categorías (con jerarquía padre-hijo y casillas de verificación); en false, como las etiquetas (texto libre). Cada término genera automáticamente su propia página de archivo: tudominio.com/tipo-proyecto/diseno-web/.
Cómo mostrar los custom post types en tu tema
WordPress resuelve la presentación mediante la jerarquía de plantillas. Para nuestro CPT proyecto buscará, por este orden:
single-proyecto.phppara la ficha individual (si no existe, usasingle.php).archive-proyecto.phppara el listado (si no existe, usaarchive.phpy despuésindex.php).taxonomy-tipo_proyecto.phppara los archivos de la taxonomía.
Si tu tema es de bloques o usas un maquetador, normalmente podrás asignar plantillas al CPT desde su propia interfaz. Y para listados a medida en cualquier plantilla o shortcode, la consulta se hace con WP_Query:
<?php
$proyectos = new WP_Query( array(
'post_type' => 'proyecto',
'posts_per_page' => 6,
'tax_query' => array(
array(
'taxonomy' => 'tipo_proyecto',
'field' => 'slug',
'terms' => 'diseno-web',
),
),
) );
if ( $proyectos->have_posts() ) :
while ( $proyectos->have_posts() ) : $proyectos->the_post();
the_title( '<h3>', '</h3>' );
the_post_thumbnail( 'medium' );
endwhile;
wp_reset_postdata();
endif;
No olvides nunca wp_reset_postdata() tras un bucle personalizado: restaura la consulta principal y evita efectos secundarios extraños en el resto de la página. La referencia completa de todos los argumentos disponibles está en la documentación oficial de post types de developer.wordpress.org.
Campos personalizados: los datos que completan la ficha
Un CPT define el «contenedor», pero los datos específicos (precio, cliente, fecha de entrega) viven en campos personalizados (post meta). Puedes gestionarlos de tres maneras: con la caja nativa de campos personalizados (espartana pero funcional), con código mediante register_post_meta() y get_post_meta(), o con plugins especializados como Advanced Custom Fields (ACF) o Meta Box, que generan interfaces de edición cómodas con validación y tipos de campo avanzados. Para proyectos serios, la combinación CPT por código + ACF para los campos es probablemente el estándar del sector.
<?php
// Registrar un campo y exponerlo en la REST API:
register_post_meta( 'proyecto', 'cliente', array(
'type' => 'string',
'single' => true,
'show_in_rest' => true,
'sanitize_callback' => 'sanitize_text_field',
) );
// Leerlo en la plantilla:
$cliente = get_post_meta( get_the_ID(), 'cliente', true );
SEO y custom post types: lo que debes revisar
Un CPT bien planteado es una bendición para el SEO: genera archivos limpios, URLs semánticas y estructura clara. Pero conviene revisar cuatro puntos:
- Sitemap: comprueba que tu plugin SEO incluye el nuevo tipo de contenido en el sitemap XML. Tanto Yoast como Rank Math, del que analizamos su versión gratuita, detectan los CPT públicos y permiten activarlos o excluirlos por tipo.
- Indexación selectiva: si el CPT es contenido de apoyo (testimonios, bloques reutilizables), márcalo como no indexable o directamente regístralo con
public => false. - Slug con intención:
/proyectos/dice más que/cpt_portfolio/. El slug del rewrite es una decisión SEO, y cambiarlo después implica redirecciones. - Contenido en el archivo: la página de archivo generada automáticamente suele ser un simple listado; valorar una página con texto introductorio propio puede marcar la diferencia para posicionar la keyword principal del tipo de contenido.
Preguntas frecuentes
¿Qué pasa con el contenido si desactivo el plugin que registra el CPT?
Nada se borra: los elementos siguen en la base de datos. Simplemente dejan de mostrarse en el escritorio y sus URLs devuelven 404, porque WordPress ya no reconoce ese tipo de contenido. Al reactivar el registro (plugin o snippet), todo vuelve a aparecer intacto. Por eso es importante mantener el registro en algo independiente del tema.
¿Custom post type o categorías? Sigo sin tener claro cuál usar
Usa categorías cuando quieras organizar artículos del blog que comparten formato. Usa un CPT cuando el contenido tenga naturaleza propia: campos distintos, plantilla distinta y sentido como sección independiente de la web. Una pista práctica: si te descubres queriendo ocultar esas «entradas» del blog principal, casi seguro que deberían ser un custom post type.
¿Cuántos custom post types puedo crear?
No hay límite técnico relevante: todos comparten la tabla wp_posts y el coste de registrar cada tipo es mínimo. El límite razonable es organizativo: si pasas de seis u ocho tipos, revisa si algunos no deberían ser en realidad taxonomías o campos de un mismo tipo. Reserva nombres con prefijo (por ejemplo bw_proyecto) si distribuyes tu código, para evitar colisiones con otros plugins.
¿Por qué mis custom post types dan error 404?
En el 95 % de los casos, por las reglas de reescritura: WordPress aún no ha «aprendido» las URLs nuevas. Ve a Ajustes → Enlaces permanentes y guarda sin cambiar nada. Si persiste, revisa que public sea true, que el slug del rewrite no choque con una página existente y que el registro se ejecute en el hook init en cada carga, no solo en la activación.
Conclusión
Los custom post types de WordPress son la herramienta que convierte un blog en un verdadero CMS a medida: porfolios, catálogos, directorios o academias, cada contenido con su estructura, sus URLs y su lugar en el escritorio. La receta profesional cabe en tres pasos: registrar el tipo con register_post_type() en el hook init (y guardar los enlaces permanentes), clasificarlo con taxonomías propias mediante register_taxonomy(), y completar las fichas con campos personalizados. A partir de ahí, la jerarquía de plantillas y WP_Query te dan control total sobre cómo se muestra todo. Empieza con un solo tipo de contenido real de tu proyecto, regístralo por código en un snippet o plugin propio, y comprueba en el escritorio lo que cambia gestionar «proyectos» de verdad en lugar de entradas disfrazadas. Esa claridad estructural la agradecerás tú, la agradecerán tus clientes y la agradecerá Google.