trabajando en wordpress

Crea tu propio Template en WordPress para mostrar tus Proyectos

Ayer me vi en la necesidad de tener que mostrar mis proyectos creados en WordPress y poder mostrarlos a través de un archivo JSON, en un template propio creado en mi propio child-theme, sé que quiza no es algo normal o algo que alguien quiera hacer, pero te ahorras plugins, e incluso comprar un theme que haga algo que puedes hacer tú mismo sin problemas.

Bien, comencemos en este tutorial avanzado (porque si necesitas conocer ciertas cositas que te explico más adelante), vamos a desglosar paso a paso cómo construí un sistema para mostrar información de proyectos individuales directamente desde archivos JSON, utilizando URLs limpias y amigables como tusitio.com/proyectos/nombre-del-proyecto. Exploraremos el poder de las reglas de reescritura (Rewrite Rules), las variables de consulta (Query Vars) y cómo indicarle a WordPress que use una plantilla personalizada específica para estas URLs, todo sin depender de los CPTs tradicionales.

Índice de Contenido
  1. Prerrequisitos - Opcional pero recomendado 😅
  2. ¿Qué vamos a construir? 🛠
  3. Paso 1: Preparando el Terreno - La estructura de Datos (JSON)
  4. Paso 2: Creando URL amigables - Las reglas de Reescritura
  5. Paso 3: Registrando Nuestra Variable - query_vars
  6. Paso 4: Diciéndole a WordPress que plantilla usar - El filtro
  7. Paso 5: La plantilla single-proyectos.php
  8. Conclusión

Prerrequisitos - Opcional pero recomendado 😅

Antes de empezar, asumiré que tienes conocimientos básicos de:

  • PHP (no necesitas saber mucho)
  • La estructura de archivos de un tema de WordPress (y preferiblemente el uso de temas hijo).
  • Cómo editar archivos de tu tema (por ejemplo, functions.php y crear nuevos archivos de plantilla).
  • Un entorno de desarrollo local de WordPress para experimentar sin riesgos (yo lo hice desde el mismo editor de wordpress en tiempo real).

¿Qué vamos a construir? 🛠

Template en WordPress manual sin plugins

Bien, lo que queremos lograr es que al visitar una URL como carlosjulian.mx/proyectos/fisimat, WordPress:

  1. Reconozca esta estructura de URL personalizada.
  2. Entienda que fisimat es el identificador (slug) de un proyecto específico.
  3. Cargue una plantilla PHP diseñada a medida (single-proyectos.php).
  4. Dentro de esa plantilla, localice y lea un archivo JSON llamado fisimat.json ubicado en nuestro tema.
  5. Muestre la información contenida en ese archivo JSON de forma estructurada y estilizada.

Ahora, quizá tu pregunta sea ¿Por qué este enfoque en lugar de CPTs?, es cierto, si bien los Custom Post Types son la solución estándar y a menudo la mejor manera para el contenido estructurado en WordPress, pero te diré porque elegí esta forma:

  • Los datos provienen de una fuente externa que ya genera JSON.
  • Necesitas una solución muy ligera para un conjunto de datos simple y no requieres la interfaz de administración de WordPress para gestionarlos.
  • Estás migrando un sitio estático con datos en JSON.
  • ¡Simplemente quieres aprender cómo funcionan estas partes internas de WordPress!

Nota: Si tienes decenas de proyectos hechos quizá la solución sea usar un CPTs, pero si solo tienes proyectos menor a 5, honestamente te recomiendo hacerlo como este tutorial.

Paso 1: Preparando el Terreno - La estructura de Datos (JSON)

Primero, necesitamos definir cómo se verá nuestra información. Usaremos archivos JSON, uno por cada proyecto. Este formato es ligero, muy fácil de entender con PHP. Crearemos una carpeta dentro de nuestro tema hijo (¡siempre usa un tema hijo para modificaciones!), por ejemplo: wp-content/themes/tu-tema-hijo/assets/data/.

Raíz de mi carpeta de mi web en CPANEL

Dentro de esa carpeta, cada proyecto tendrá su archivo. Por ejemplo, fisimat.json:

Tutorial paso 1 - Crear los 3 archivso JSON
// wp-content/themes/tu-tema-hijo/assets/data/fisimat.json
{
  "nombre": "Fisimat",
  "descripcion": "Fisimat es un portal web líder en español dedicado a la enseñanza y divulgación de la física y las matemáticas...",
  "objetivo": "Facilitar el aprendizaje autónomo...",
  "visitas_anuales": 2300000,
  "usuarios_destino": "Principalmente estudiantes de preparatoria...",
  "tecnologias": [
    "WordPress (CMS)",
    "PHP",
    // ... más tecnologías
  ],
  "logros": [
    "Alcanzar y mantener más de 2.3 millones de visitas orgánicas anuales.",
    // ... más logros
  ],
  "redes_sociales": {
    "Facebook": "https://facebook.com/fisimat",
    "Twitter": "https://twitter.com/fisimat",
    "YouTube": "URL_YOUTUBE"
  },
  "galeria": [
    "URL_IMAGEN_1",
    "URL_IMAGEN_2"
    // ... más imágenes
  ],
  "enlaces": {
    "Visita Fisimat.com.mx": "https://fisimat.com.mx",
    "Canal de YouTube Oficial": "URL_YOUTUBE"
    // ... más enlaces
  }
}

 Debes tomar en cuenta algunas cosas sobre el archivo JSON:

  • Usa claves descriptivas (nombre, descripcion, etc.).
  • Almacena números como números (visitas_anuales: 2300000), no como texto.
  • Utiliza arrays [] para listas (como tecnologias, logros, galeria).
  • Utiliza objetos {} (arrays asociativos en PHP) para pares clave-valor (como redes_sociales, enlaces).

Paso 2: Creando URL amigables - Las reglas de Reescritura

Ahora necesitamos que WordPress entienda nuestra URL personalizada, es decir:

tusitio.com/proyectos/nombre-proyecto

Aquí es donde entra el concepto de Rewrite Rules. Añadiremos el siguiente código a nuestro archivo functions.php del tema hijo:

// functions.php

function cj_proyectos_rewrite_rules() {
    add_rewrite_rule(
        '^proyectos/([^/]+)/?$', // 1. La Expresión Regular
        'index.php?pagename=proyectos&proyecto=$matches[1]', // 2. El Destino
        'top' // 3. La Prioridad
    );
}
add_action('init', 'cj_proyectos_rewrite_rules');

Explicación del código:

  1. ^proyectos/([^/]+)/?$: Esta es una expresión regular (regex) que busca URLs que:
    • Empiecen (^) con proyectos/.
    • Seguido de uno o más caracteres que NO sean una barra / ([^/]+). Esto captura el slug del proyecto (ej. fisimat) y lo guarda en $matches[1].
    • Opcionalmente (?) puede terminar con una barra /.
    • Y que sea el final de la URL ($).
  2. 'index.php?pagename=proyectos&proyecto=$matches[1]': Le dice a WordPress que, internamente, trate esta URL como si fuera la página con slug proyectos (¡asegúrate de tener una página publicada con ese slug!) y que añada un parámetro de consulta llamado proyecto con el valor capturado por la regex ($matches[1], que es nuestro slug).
  3. 'top': Indica que esta regla debe tener prioridad sobre las reglas por defecto de WordPress.
¡Importante! Después de añadir o modificar reglas de reescritura, necesitas "refrescarlas". La forma más fácil es ir a Ajustes -> Enlaces permanentes en el administrador de WordPress y simplemente hacer clic en Guardar cambios.

Paso 3: Registrando Nuestra Variable - query_vars

WordPress necesita reconocer oficialmente nuestro parámetro de consulta personalizado proyecto que definimos en la regla de reescritura. Lo hacemos con el filtro query_vars:

Veamos el código:

// functions.php 

function cj_proyectos_query_vars($vars) {
    $vars[] = 'proyecto'; // Añade 'proyecto' a la lista de variables permitidas
    return $vars;
}
add_filter('query_vars', 'cj_proyectos_query_vars');

Este código, solamente añade nuestra variable proyecto a la lista de variables que WordPress entiende y procesa. 🤓

Paso 4: Diciéndole a WordPress que plantilla usar - El filtro

Ahora que WordPress entiende la URL y tiene el slug del proyecto en una variable, necesitamos decirle que cargue nuestra plantilla personalizada single-proyectos.php en lugar de la plantilla de la página proyectos.

El camino incorrecto (y por qué): Podríamos sentir la tentación de usar el hook template_redirect para incluir manualmente el header, la plantilla y el footer. ¡No lo hagas! Esto puede saltarse muchas funciones importantes de WordPress y causar problemas (ya me pasó 😅).

El camino correcto: Usar el filtro template_include. Este filtro se ejecuta justo antes de que WordPress cargue el archivo de plantilla y nos permite cambiar cuál archivo se va a usar.

// functions.php (continuación)

function cj_proyectos_template_include( $template ) {
    // Verificamos si nuestra variable 'proyecto' está presente en la consulta actual
    if ( get_query_var('proyecto') ) {
        // Construimos la ruta a nuestra plantilla personalizada DENTRO DEL TEMA HIJO
        $new_template = get_stylesheet_directory() . '/single-proyectos.php';

        // Verificamos si el archivo de plantilla realmente existe
        if ( file_exists( $new_template ) ) {
            // Si existe, devolvemos la ruta a nuestra plantilla. WordPress la usará.
            return $new_template;
        }
    }
    // Si no es una URL de proyecto o la plantilla no existe,
    // devolvemos la plantilla que WordPress iba a usar originalmente.
    return $template;
}
// Añadimos nuestro filtro con una prioridad alta (99)
add_filter( 'template_include', 'cj_proyectos_template_include', 99 );

Puntos importantes:

  • Usamos get_query_var('proyecto') para detectar si estamos en una URL de proyecto.
  • Usamos get_stylesheet_directory() para obtener la ruta al directorio de nuestro tema activo (el tema hijo), que es donde debe estar single-proyectos.php. ¡No uses get_template_directory() aquí si usas un tema hijo!
  • Verificamos si el archivo existe (file_exists) antes de intentar usarlo.

Paso 5: La plantilla single-proyectos.php

Pues llegamos casi al final del tutorial, y lo que falta es la creación de la plantilla que muestra a estos archivos JSON.

Este es el archivo que realmente mostrará la información de nuestro proyecto. Debe estar ubicado en la raíz de tu tema hijo (ej. wp-content/themes/tu-tema-hijo/single-proyectos.php).

<?php
// single-proyectos.php

get_header(); // Carga el encabezado estándar del tema
?>

<div id="primary" class="content-area">
	<main id="main" class="site-main" role="main">

		<?php
		// 1. Obtener el slug del proyecto de forma segura
		$proyecto_slug = sanitize_text_field( get_query_var('proyecto') );

		if ( !empty( $proyecto_slug ) ) :

			// 2. Construir la ruta al archivo JSON (¡usando el tema hijo!)
			$proyecto_json_path = get_stylesheet_directory() . "/assets/data/{$proyecto_slug}.json";

			// 3. Verificar si el archivo JSON existe
			if ( file_exists( $proyecto_json_path ) ) :

				// 4. Leer y decodificar el JSON
				$json_data = file_get_contents( $proyecto_json_path );
				$proyecto = json_decode( $json_data, true ); // true para array asociativo

				// 5. Verificar errores de decodificación JSON
				if ( json_last_error() === JSON_ERROR_NONE ) :

                    // 6. ¡Éxito! Mostrar los datos usando HTML y escapado seguro
					?>
					<article class="proyecto-individual-wrapper post">
                        <div class="entry-content">
                            <div class="wrap proyecto-individual">

                                <h1><?= esc_html( $proyecto['nombre'] ?? 'Proyecto Sin Nombre' ) ?></h1>
                                <p class="descripcion"><?= wp_kses_post( $proyecto['descripcion'] ?? '' ) ?></p>

                                <div class="datos-proyecto">
                                    <p><strong>Objetivo:</strong> <?= esc_html( $proyecto['objetivo'] ?? '' ) ?></p>
                                    <p><strong>Visitas anuales:</strong> <?= isset($proyecto['visitas_anuales']) ? number_format( (int) $proyecto['visitas_anuales'] ) : 'N/A' ?></p>
                                    <p><strong>Usuarios destinatarios:</strong> <?= esc_html( $proyecto['usuarios_destino'] ?? '' ) ?></p>
                                    <?php if (!empty($proyecto['tecnologias']) && is_array($proyecto['tecnologias'])): ?>
                                        <p><strong>Tecnologías usadas:</strong> <?= implode(', ', array_map('esc_html', $proyecto['tecnologias'])) ?></p>
                                    <?php endif; ?>
                                    <?php // ... (resto del HTML para logros, redes, enlaces, galería como en el ejemplo) ... ?>
                                </div>

                                <?php // ... (Secciones de Redes Sociales, Enlaces, Galería) ... ?>

                            </div>
                        </div>
					</article>
					<?php

				else : // Error de JSON
					echo '<p>Error: El archivo JSON del proyecto está dañado.</p>';
				endif; // Fin error JSON

			else : // Archivo JSON no encontrado
				echo "<p>El proyecto solicitado (<code>" . esc_html($proyecto_slug) . "</code>) no fue encontrado. ❌</p>";
                // Considera mostrar una plantilla 404 aquí para mejor SEO y UX
			endif; // Fin file_exists

		else : // No se proporcionó slug
			echo "<p>No se ha especificado un proyecto.</p>";
		endif; // Fin !empty slug
		?>

	</main>
</div>

<?php
get_footer(); // Carga el pie de página estándar del tema
?>

Puntos clave de la plantilla:

  • Usa get_header() y get_footer() para integrarse con tu tema.
  • Obtiene el slug con get_query_var('proyecto') y lo sanea con sanitize_text_field.
  • Construye la ruta al JSON con get_stylesheet_directory().
  • Usa file_exists para verificar la existencia del archivo.
  • Usa file_get_contents para leer y json_decode($data, true) para convertir a array PHP.
  • Crucial: Verifica json_last_error() después de decodificar.
  • Seguridad: Escapa TODA la salida con esc_html(), esc_url(), esc_attr(), wp_kses_post() o number_format() según corresponda para prevenir ataques XSS.
  • Proporciona mensajes de error claros si el archivo no se encuentra o el JSON es inválido. Considera implementar una respuesta 404 real para archivos no encontrados.

Conclusión

Llegamos al final del artículo/tutorial para personalizar muchas cosas con WordPress Avanzado, y ahora ya puedes mostrar contenido desde archivos JSON usando URLS amigables. Recuerda que es importante practicar en un entorno local y no en producción. ¿Qué fue lo que aprendimos?

  • add_rewrite_rule: Para mapear URLs personalizadas.
  • query_vars: Para que WordPress reconozca nuestros parámetros.
  • template_include: El filtro correcto para seleccionar plantillas dinámicamente.
  • Funciones de manejo de archivos y JSON en PHP.

Recuerda siempre:

  • Usar Temas Hijo: Nunca modifiques directamente los archivos de un tema padre.
  • Elegir el Hook Correcto: template_include es preferible a template_redirect para cargar plantillas.
  • Rutas Correctas: get_stylesheet_directory() para archivos en tu tema activo (hijo).
  • Seguridad Primero: ¡Sanear entradas y escapar salidas SIEMPRE!
  • Manejo de Errores: Proporciona feedback útil cuando algo falla.
  • Contexto: Este método es una herramienta más en tu arsenal. Evalúa si es la solución adecuada comparada con CPTs o la REST API para cada necesidad específica.

Espero que te haya servido, un gusto y un abrazo.

Estos temas te pueden interesar

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Tu puntuación: Útil

Subir