Como crear un template de WordPress desde 0

Como crear un template de WordPress desde 0

Contenidos ocultar
1 Como crear un template de WordPress desde 0

Introducción a los Templates de WordPress

¡Bienvenido al emocionante mundo de la creación de temas de WordPress! Si estás aquí, es porque tienes interés en personalizar la apariencia de tu sitio web o blog, y eso es genial. Los templates (o temas) son el corazón visual de cualquier sitio WordPress, y aprender a crearlos desde cero te dará un control total sobre el diseño y la funcionalidad. Antes de sumergirnos en el código, es importante entender qué son exactamente los templates de WordPress y por qué son tan importantes. En esencia, un template es un conjunto de archivos que trabajan juntos para controlar la presentación de tu contenido. Piensa en ellos como la "piel" de tu sitio web. Mientras que WordPress se encarga de gestionar el contenido (entradas, páginas, comentarios, etc.), el template se encarga de mostrar ese contenido de una manera atractiva y organizada. ¿Por qué crear tu propio template en lugar de usar uno ya existente? Hay varias razones:
  • Personalización completa: Un template hecho a medida te permite diseñar cada elemento exactamente como lo deseas. No estás limitado por las opciones de un tema preexistente. Puedes controlar cada píxel, cada color, cada fuente... ¡todo!
  • Aprendizaje profundo: Construir un template desde cero te obliga a entender cómo funciona WordPress internamente. Aprenderás sobre la jerarquía de plantillas, el famoso "Loop" de WordPress, las funciones esenciales y mucho más. Este conocimiento te será invaluable, incluso si en el futuro decides usar temas preexistentes.
  • Optimización del rendimiento: Los templates personalizados suelen ser más ligeros y rápidos que los temas multifunción cargados de opciones que quizás no necesites. Al construir solo lo que necesitas, reduces la carga del servidor y mejoras la velocidad de tu sitio.
  • Control total del código: Sabes exactamente qué código hay en tu tema, lo que facilita la depuración, el mantenimiento y las futuras actualizaciones. No hay sorpresas ocultas ni código inflado.
  • Desarrollo profesional: Si aspiras a convertirte en desarrollador de WordPress, crear tus propios templates es una habilidad fundamental. Te abrirá puertas a trabajos freelance, proyectos personalizados y una mayor comprensión del ecosistema WordPress.
Un template de WordPress no es solo un archivo, sino un conjunto de ellos, la mayoría en formato PHP, que interactúan entre sí:
  • Archivos PHP: Estos archivos contienen el código que define la estructura y el contenido de tus páginas. Utilizan una combinación de HTML y funciones de WordPress para mostrar el contenido dinámicamente.
  • Hoja de estilos (style.css): Este archivo contiene el código CSS que define la apariencia visual de tu sitio: colores, fuentes, diseño, etc. Además, contiene información crucial sobre el tema (nombre, autor, versión, etc.) en su cabecera.
  • Archivos JavaScript (opcionales): Estos archivos añaden interactividad a tu sitio. Puedes usarlos para crear efectos, animaciones, validaciones de formularios, etc.
  • Imágenes (opcional): Puedes incluir imágenes para el logo, iconos, fondos, etc.
En las siguientes secciones, exploraremos cada uno de estos elementos en detalle y te guiaremos paso a paso en la creación de tu propio template de WordPress. ¡Prepárate para construir algo increíble!

Preparación del Entorno de Desarrollo

Antes de empezar a escribir código, necesitamos preparar nuestro "taller". Un entorno de desarrollo adecuado nos facilitará mucho la vida, permitiéndonos trabajar de forma eficiente y segura. No te preocupes, no necesitas ser un experto en servidores para configurar uno. Vamos a ver los pasos esenciales:

Instalación de un Servidor Local (XAMPP, MAMP, Local by Flywheel)

Para desarrollar un tema de WordPress, necesitas un servidor web, una base de datos y PHP. En lugar de usar un servidor remoto (como el que usarías para alojar tu sitio web en línea), vamos a instalar un servidor local en tu propio ordenador. Esto tiene varias ventajas:
  • Es más rápido: Trabajar en local es mucho más rápido que subir archivos a un servidor remoto cada vez que haces un cambio.
  • Es más seguro: No necesitas una conexión a Internet para trabajar, y tu sitio no estará expuesto a posibles ataques.
  • Es gratis: No tienes que pagar por un hosting mientras desarrollas.
Hay varias opciones para crear un servidor local. Aquí te presento tres de las más populares:
  • XAMPP (Windows, macOS, Linux): Es una de las opciones más antiguas y populares. Es un paquete que incluye Apache (el servidor web), MySQL (la base de datos), PHP y Perl. Es un poco más técnico de configurar, pero es muy potente y versátil.Web Oficial: https://www.apachefriends.org/es/index.html
  • MAMP (Windows, macOS): Similar a XAMPP, pero con una interfaz un poco más amigable. También incluye Apache, MySQL, PHP y otras herramientas. Tiene una versión gratuita y una versión de pago con más características.Web Oficial: https://www.mamp.info/en/downloads/
  • Local by Flywheel (Windows, macOS, Linux): Es una opción más moderna y específica para WordPress. Es muy fácil de usar y configurar, y te permite crear sitios WordPress con unos pocos clics. Es ideal para principiantes.Web Oficial: https://localwp.com/
Elige la opción que te resulte más cómoda. La instalación suele ser sencilla: descarga el instalador, sigue las instrucciones y listo. Una vez instalado, tendrás un panel de control desde el que podrás iniciar y detener los servicios (Apache, MySQL, etc.).

Instalación de WordPress

Una vez que tienes tu servidor local funcionando, necesitas instalar WordPress. Hay dos formas principales de hacerlo:
  • Instalación manual:
    1. Descarga la última versión de WordPress desde wordpress.org.
    2. Descomprime el archivo ZIP en la carpeta de tu servidor local donde se alojarán los sitios web (por ejemplo, "htdocs" en XAMPP, o la carpeta que hayas configurado en MAMP o Local).
    3. Crea una base de datos para tu sitio WordPress. Puedes hacerlo a través de phpMyAdmin, una herramienta que suele venir incluida con XAMPP y MAMP. Accede a phpMyAdmin desde el panel de control de tu servidor local.
    4. Renombra el archivo
      wp-config-sample.php
      a
      wp-config.php
      .
    5. Abre el archivo
      wp-config.php
      y edita las siguientes líneas con los datos de tu base de datos:
      • DB_NAME
        : El nombre de la base de datos que creaste.
      • DB_USER
        : El nombre de usuario de la base de datos (por defecto, suele ser "root").
      • DB_PASSWORD
        : La contraseña de la base de datos (si la has configurado).
      • DB_HOST
        : El host de la base de datos (normalmente, "localhost").
    6. Abre tu navegador y escribe la dirección de tu sitio local (por ejemplo,
      http://localhost/misitio
      ). Sigue las instrucciones de instalación de WordPress.
  • Instalación con un clic (Local by Flywheel): Si usas Local by Flywheel, la instalación es mucho más sencilla. Simplemente haz clic en el botón "+" para crear un nuevo sitio, elige un nombre, y Local se encargará de todo lo demás.
Una vez completados los pasos anteriores tendras tu entorno de wordpress listo.

Elección de un Editor de Código (VS Code, Sublime Text, Atom)

Para escribir y editar el código de tu tema, necesitarás un buen editor de código. Un editor de código te proporciona herramientas como resaltado de sintaxis, autocompletado, búsqueda y reemplazo, y muchas otras funciones que te facilitarán la vida. Aquí tienes algunas opciones populares:
  • Visual Studio Code (VS Code) (Windows, macOS, Linux): Es uno de los editores de código más populares y potentes. Es gratuito, de código abierto, y tiene una gran comunidad y una enorme cantidad de extensiones disponibles. Es altamente recomendable.Web Oficial: https://code.visualstudio.com/
  • Sublime Text (Windows, macOS, Linux): Es otro editor muy popular, conocido por su velocidad y su interfaz minimalista. Es de pago, pero puedes usarlo de forma gratuita con algunas limitaciones.Web Oficial: https://www.sublimetext.com/
  • Atom (Windows, macOS, Linux): Es un editor de código abierto creado por GitHub. Es muy personalizable y tiene una gran comunidad. Aunque es potente, puede ser un poco más lento que VS Code o Sublime Text. (Descontinuado).Web Oficial: https://atom.io/
Mi recomendación personal es VS Code. Es el que yo uso, y el que usan la mayoría de los desarrolladores de WordPress. Pero siéntete libre de probar otros y elegir el que más te guste. Una vez que hayas instalado tu editor de código, puedes abrir la carpeta de tu tema de WordPress (que estará dentro de la carpeta
wp-content/themes
de tu instalación de WordPress) y empezar a trabajar. ¡Con esto, ya tienes tu entorno de desarrollo listo! En la siguiente sección, empezaremos a construir la estructura básica de nuestro tema.

Estructura Básica de un Template de WordPress

Ahora que tenemos nuestro entorno de desarrollo listo, ¡es hora de empezar a construir! Vamos a crear la estructura básica de nuestro tema, que servirá como esqueleto sobre el que construiremos el resto. Un tema de WordPress, en su forma más simple, necesita muy pocos archivos para funcionar. Pero a medida que agreguemos funcionalidad, iremos añadiendo más.

Archivos Fundamentales (style.css, index.php)

Hay dos archivos absolutamente esenciales para que un tema de WordPress sea reconocido como tal:
  • style.css: Este archivo no solo contiene los estilos CSS que darán forma a la apariencia de tu sitio, sino que también contiene información crucial sobre el tema en forma de comentario en la cabecera del archivo. WordPress lee esta cabecera para obtener información como el nombre del tema, el autor, la versión, la descripción, etc. Sin esta cabecera, WordPress no reconocerá tu tema.
  • index.php: Este es el archivo de plantilla principal. Si no existe ningún otro archivo de plantilla, WordPress usará index.php para mostrar todo el contenido de tu sitio (entradas, páginas, archivos, etc.). Es el archivo de "respaldo" por defecto.
Vamos a crear estos dos archivos. Dentro de la carpeta
wp-content/themes
de tu instalación de WordPress, crea una nueva carpeta con el nombre de tu tema (por ejemplo,
mi_tema_personalizado
). Dentro de esta carpeta, crea los archivos
style.css
e
index.php
.

Carpetas Esenciales (images, js, css - opcionales)

Aunque no son estrictamente necesarias para que el tema funcione, es una buena práctica organizar tus archivos en carpetas. Esto te ayudará a mantener tu código ordenado y fácil de encontrar. Las carpetas más comunes son:
  • images: Aquí puedes guardar todas las imágenes que uses en tu tema (logo, iconos, fondos, etc.).
  • js: Aquí puedes guardar tus archivos JavaScript.
  • css: Aunque ya tenemos el style.css, a veces es útil crear archivos CSS adicionales para organizar mejor tus estilos, por ejemplo, un archivo para los estilos de la barra lateral, otro para los estilos del pie de página, etc. Luego, puedes importar estos archivos en tu style.css principal o encolarlos mediante functions.php (lo veremos más adelante).
  • inc o includes: Se utiliza a menudo para almacenar archivos PHP que contienen funciones personalizadas, clases u otras lógicas que no son directamente plantillas, pero que son esenciales para la funcionalidad del tema.
  • template-parts: Contiene fragmentos de plantillas que se pueden reutilizar en diferentes partes del tema, como el encabezado, el pie de página, la barra lateral, etc.
Crea estas carpetas dentro de la carpeta de tu tema, si lo deseas.

La Hoja de Estilos (style.css) - Cabecera del Tema

Abre el archivo
style.css
y añade la siguiente cabecera. Esta es la parte más importante de este archivo, ya que es lo que WordPress usa para identificar tu tema.

/*
Theme Name: Mi Tema Personalizado
Theme URI:  https://example.com/mi-tema-personalizado/
Author: Tu Nombre
Author URI: https://example.com/
Description: Un tema de WordPress personalizado creado desde cero.
Version: 1.0.0
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Tags: blog, custom-background, custom-logo, custom-menu, featured-images, threaded-comments, translation-ready
Text Domain: mi-tema-personalizado
*/

/* Aquí van tus estilos CSS */

body {
    font-family: sans-serif;
    line-height: 1.6;
    color: #333;
}
Vamos a desglosar cada línea:
  • Theme Name: El nombre de tu tema (obligatorio).
  • Theme URI: La URL de la página web de tu tema (opcional).
  • Author: Tu nombre (opcional).
  • Author URI: La URL de tu página web (opcional).
  • Description: Una breve descripción de tu tema (opcional).
  • Version: El número de versión de tu tema (opcional).
  • License: La licencia de tu tema (opcional, pero recomendable). La mayoría de los temas de WordPress usan la Licencia Pública General de GNU (GPL).
  • License URI: La URL de la licencia (opcional).
  • Tags: Etiquetas que describen tu tema. Estas etiquetas se usan en el directorio de temas de WordPress.org (opcional).
  • Text Domain: El dominio de texto de tu tema. Se usa para la internacionalización (traducción) de tu tema (opcional, pero muy recomendable). Debe ser único y coincidir con el nombre de la carpeta de tu tema (sin espacios ni caracteres especiales).
Después de la cabecera, puedes añadir tus estilos CSS. Por ahora, he añadido un estilo básico para el cuerpo del documento.

El Archivo Principal (index.php)

Abre el archivo
index.php
y añade el siguiente código:

<?php
/**
 * The main template file
 *
 * This is the most generic template file in a WordPress theme
 * and one of the two required files for a theme (the other being style.css).
 * It is used to display a page when nothing more specific matches a query.
 * E.g., it puts together the home page when no home.php file exists.
 *
 * @link https://developer.wordpress.org/themes/basics/template-hierarchy/
 *
 * @package mi_tema_personalizado
 */

get_header(); ?>

    <main id="primary" class="site-main">

        <?php
        if ( have_posts() ) :

            if ( is_home() &amp;&amp; ! is_front_page() ) :
                ?>
                <header>
                    <h1 class="page-title screen-reader-text"><?php single_post_title(); ?></h1>
                </header>
                <?php
            endif;

            /* Start the Loop */
            while ( have_posts() ) :
                the_post();

                /*
                 * Include the Post-Type-specific template for the content.
                 * If you want to override this in a child theme, then include a file
                 * called content-___.php (where ___ is the Post Type name) and that will be used instead.
                 */
                get_template_part( 'template-parts/content', get_post_type() );

            endwhile;

            the_posts_navigation();

        else :

            get_template_part( 'template-parts/content', 'none' );

        endif;
        ?>

    </main><!-- #main -->

<?php
get_sidebar();
get_footer();
?>
Este código puede parecer intimidante al principio, pero vamos a desglosarlo:
  • Comentarios del archivo: Es buena practica comentar el código; en este caso, se explica para qué sirve este archivo.
  • get_header(): Esta función incluye el archivo
    header.php
    de tu tema (si existe). El
    header.php
    suele contener el encabezado de tu sitio (etiqueta
    <head>
    , menú de navegación, etc.). Lo crearemos en la siguiente sección.
  • :
    Esta etiqueta HTML5 define el contenido principal de tu página. Le hemos añadido un ID ("primary") y una clase ("site-main") para poder darle estilo con CSS.
  • if ( have_posts() ) : Esta es una función condicional de WordPress que comprueba si hay entradas (posts) para mostrar. Si hay entradas, se ejecuta el código dentro del if. Si no hay entradas, se ejecuta el código dentro del else.
  • while ( have_posts() ) : the_post();: Este es el famoso "Loop" de WordPress. Recorre todas las entradas que coinciden con la consulta actual y las muestra una por una. La función the_post() prepara la entrada actual para que podamos acceder a sus datos (título, contenido, etc.).
  • get_template_part( 'template-parts/content', get_post_type() ): Esta función incluye un archivo de plantilla parcial. En este caso, estamos incluyendo un archivo llamado
    content.php
    (o
    content-{post-type}.php
    , si existe) que se encuentra dentro de la carpeta
    template-parts
    . Este archivo se encargará de mostrar el contenido de cada entrada. Lo crearemos más adelante.
  • the_posts_navigation(): Esta función muestra la navegación entre páginas (si hay más entradas de las que caben en una sola página).
  • get_template_part( 'template-parts/content', 'none' ): Si no hay entradas para mostrar, se incluye el archivo
    content-none.php
    (que también crearemos más adelante).
  • get_sidebar(): Esta función incluye el archivo
    sidebar.php
    de tu tema (si existe). El
    sidebar.php
    suele contener la barra lateral de tu sitio.
  • get_footer(): Esta función incluye el archivo
    footer.php
    de tu tema (si existe). El
    footer.php
    suele contener el pie de página de tu sitio (copyright, enlaces, etc.).
¡Ya tienes la estructura básica de tu tema! Ahora, si vas al panel de administración de WordPress (Apariencia > Temas), deberías ver tu tema listado. Puedes activarlo, pero por ahora no mostrará mucho, ya que solo tenemos el esqueleto. En las siguientes secciones, iremos rellenando este esqueleto con más archivos y funcionalidad.

Creación de Archivos PHP Esenciales

Después de tener la estructura básica, es hora de añadir más archivos PHP para darle vida a nuestro tema. Estos archivos se encargarán de secciones específicas de tu sitio web, como el encabezado, el pie de página y la barra lateral.

header.php (El Encabezado)

El archivo
header.php
contiene el código HTML que se mostrará en la parte superior de todas las páginas de tu sitio. Normalmente, incluye:
  • La etiqueta de apertura
    <!DOCTYPE html>
    .
  • La etiqueta
    <html>
    con el atributo de idioma.
  • La etiqueta
    <head>
    con:
    • La etiqueta
      <meta charset="UTF-8">
      .
    • La etiqueta
      <meta name="viewport">
      .
    • El título de la página (
      <title>
      ).
    • Llamadas a hojas de estilo y scripts (lo veremos más adelante).
    • La función
      wp_head()
      .
  • La etiqueta de apertura
    <body>
    con la función
    body_class()
    .
  • El menú de navegación principal.
  • Un contenedor para el contenido principal (por ejemplo, un
    <div>
    con la clase "site-content").
Crea un archivo llamado
header.php
dentro de la carpeta de tu tema y añade el siguiente código:

<!DOCTYPE html>
<html <?php language_attributes(); ?>>
<head>
    <meta charset="<?php bloginfo( 'charset' ); ?>">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title><?php wp_title( '|', true, 'right' ); ?></title>
    <?php wp_head(); ?>
</head>

<body <?php body_class(); ?>>

<header id="masthead" class="site-header">
    <div class="site-branding">
        <?php
        if ( is_front_page() &amp;&amp; is_home() ) :
            ?>
            <h1 class="site-title"><a href="<?php echo esc_url( home_url( '/' ) ); ?>" rel="home"><?php bloginfo( 'name' ); ?></a></h1>
            <?php
        else :
            ?>
            <p class="site-title"><a href="<?php echo esc_url( home_url( '/' ) ); ?>" rel="home"><?php bloginfo( 'name' ); ?></a></p>
            <?php
        endif;

        $mi_tema_personalizado_description = get_bloginfo( 'description', 'display' );
        if ( $mi_tema_personalizado_description || is_customize_preview() ) :
            ?>
            <p class="site-description"><?php echo $mi_tema_personalizado_description; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></p>
        <?php endif; ?>
    </div><!-- .site-branding -->

    <nav id="site-navigation" class="main-navigation">
        <?php
        wp_nav_menu(
            array(
                'theme_location' => 'menu-principal',
                'menu_id'        => 'primary-menu',
            )
        );
        ?>
    </nav><!-- #site-navigation -->
</header><!-- #masthead -->

<div id="content" class="site-content">
Explicación del código:
  • language_attributes()
    :
    Imprime los atributos de idioma de la etiqueta
    <html>
    .
  • bloginfo( 'charset' )
    :
    Obtiene el juego de caracteres de tu sitio WordPress.
  • wp_title( '|', true, 'right' )
    :
    Muestra el título de la página actual, con un separador (|) y el nombre del sitio a la derecha.
  • wp_head()
    :
    Esta función es *muy* importante. Inserta código esencial en la etiqueta
    <head>
    , como enlaces a hojas de estilo, scripts, metadatos, etc. Muchos plugins dependen de esta función para funcionar correctamente. *Nunca* la olvides.
  • body_class()
    :
    Esta función añade clases CSS a la etiqueta
    <body>
    que describen la página actual (por ejemplo, si es la página de inicio, una entrada individual, una página de archivo, etc.). Estas clases son muy útiles para aplicar estilos CSS específicos a diferentes tipos de páginas.
  • is_front_page() &amp;&amp; is_home()
    : Verifica si la página actual es la página de inicio *y* si la página de inicio muestra las últimas entradas (en lugar de una página estática).
  • home_url( '/' )
    : Devuelve la URL de la página de inicio de tu sitio.
  • bloginfo( 'name' )
    :
    Obtiene el nombre de tu sitio WordPress.
  • get_bloginfo( 'description', 'display' )
    : Obtiene la descripción corta(tagline) de tu sitio.
  • wp_nav_menu()
    :
    Esta función muestra un menú de navegación. En este caso, estamos mostrando el menú que hemos registrado con el nombre "menu-principal" (lo registraremos en
    functions.php
    más adelante).

footer.php (El Pie de Página)

El archivo
footer.php
contiene el código HTML que se mostrará en la parte inferior de todas las páginas de tu sitio. Normalmente, incluye:
  • Información de copyright.
  • Enlaces a redes sociales (opcional).
  • La función
    wp_footer()
    .
  • La etiqueta de cierre
    </body>
    .
  • La etiqueta de cierre
    </html>
    .
Crea un archivo llamado
footer.php
dentro de la carpeta de tu tema y añade el siguiente código:

    </div><!-- #content -->

<footer id="colophon" class="site-footer">
    <div class="site-info">
        <a href="<?php echo esc_url( __( 'https://wordpress.org/', 'mi-tema-personalizado' ) ); ?>">
            <?php
            /* translators: %s: CMS name, i.e. WordPress. */
            printf( esc_html__( 'Proudly powered by %s', 'mi-tema-personalizado' ), 'WordPress' );
            ?>
        </a>
        <span class="sep"> | </span>
            <?php
            /* translators: 1: Theme name, 2: Theme author. */
            printf( esc_html__( 'Theme: %1$s by %2$s.', 'mi-tema-personalizado' ), 'mi-tema-personalizado', '<a href="https://example.com/">Tu Nombre</a>' );
            ?>
    </div><!-- .site-info -->
</footer><!-- #colophon -->

<?php wp_footer(); ?>

</body>
</html>
Explicación del código:
  • Cerramos el div
    #content
    que abrimos en el header.
  • __()
    :
    Esta función se usa para la traducción de cadenas de texto. Permite que tu tema sea traducido a otros idiomas.
  • esc_url()
    :
    Esta función "escapa" una URL, asegurándose de que sea segura. Es una buena práctica usarla siempre que muestres una URL.
  • printf()
    y
    esc_html__()
    :
    Se usan para mostrar texto traducible que puede contener variables.
  • wp_footer()
    :
    Esta función, al igual que
    wp_head()
    , es *muy* importante. Inserta código esencial en la parte inferior de tu página, justo antes de la etiqueta de cierre
    </body>
    . Muchos plugins dependen de esta función. *Nunca* la olvides.

sidebar.php (La Barra Lateral - Opcional)

El archivo
sidebar.php
contiene el código HTML de la barra lateral de tu sitio. La barra lateral suele mostrar widgets, como una lista de entradas recientes, categorías, un buscador, etc. No todos los temas tienen barra lateral. Crea un archivo llamado
sidebar.php
dentro de la carpeta de tu tema y añade el siguiente código:

<?php
/**
 * The sidebar containing the main widget area
 *
 * @link https://developer.wordpress.org/themes/basics/template-files/#template-partials
 *
 * @package mi_tema_personalizado
 */

if ( ! is_active_sidebar( 'sidebar-1' ) ) {
	return;
}
?>

<aside id="secondary" class="widget-area">
	<?php dynamic_sidebar( 'sidebar-1' ); ?>
</aside><!-- #secondary -->
Explicación del código:
  • is_active_sidebar( 'sidebar-1' )
    :
    Comprueba si la barra lateral con el ID 'sidebar-1' tiene algún widget activo. Si no tiene widgets, no se muestra nada.
  • dynamic_sidebar( 'sidebar-1' )
    :
    Esta función muestra los widgets que se han añadido a la barra lateral con el ID 'sidebar-1'. Registraremos esta barra lateral en `functions.php` más adelante.

functions.php (Funcionalidades del Tema)

El archivo
functions.php
es el corazón de la funcionalidad de tu tema. Aquí es donde puedes:
  • Registrar menús de navegación.
  • Registrar áreas de widgets.
  • Añadir soporte para características del tema (como imágenes destacadas, formatos de entrada, etc.).
  • "Encolar" (cargar) hojas de estilo y scripts.
  • Crear funciones personalizadas.
  • Y mucho más...
Crea un archivo llamado
functions.php
dentro de la carpeta de tu tema y añade el siguiente código:

<?php
/**
 * mi_tema_personalizado functions and definitions
 *
 * @link https://developer.wordpress.org/themes/basics/theme-functions/
 *
 * @package mi_tema_personalizado
 */

if ( ! defined( '_S_VERSION' ) ) {
	// Replace the version number of the theme on each release.
	define( '_S_VERSION', '1.0.0' );
}

/**
 * Sets up theme defaults and registers support for various WordPress features.
 *
 * Note that this function is hooked into the after_setup_theme hook, which
 * runs before the init hook. The init hook is too late for some features, such
 * as indicating support for post thumbnails.
 */
function mi_tema_personalizado_setup() {
	/*
		* Make theme available for translation.
		* Translations can be filed in the /languages/ directory.
		* If you're building a theme based on mi_tema_personalizado, use a find and replace
		* to change 'mi-tema-personalizado' to the name of your theme in all template files.
		*/
	load_theme_textdomain( 'mi-tema-personalizado', get_template_directory() . '/languages' );

	// Add default posts and comments RSS feed links to head.
	add_theme_support( 'automatic-feed-links' );

	/*
		* Let WordPress manage the document title.
		* By adding theme support, we declare that this theme does not use a
		* hard-coded <title> tag in the document head, and expect WordPress to
		* provide it for us.
		*/
	add_theme_support( 'title-tag' );

	/*
		* Enable support for Post Thumbnails on posts and pages.
		*
		* @link https://developer.wordpress.org/themes/functionality/featured-images-post-thumbnails/
		*/
	add_theme_support( 'post-thumbnails' );

	// This theme uses wp_nav_menu() in one location.
	register_nav_menus(
		array(
			'menu-principal' => esc_html__( 'Menú Principal', 'mi-tema-personalizado' ),
		)
	);

	/*
		* Switch default core markup for search form, comment form, and comments
		* to output valid HTML5.
		*/
	add_theme_support(
		'html5',
		array(
			'search-form',
			'comment-form',
			'comment-list',
			'gallery',
			'caption',
			'style',
			'script',
		)
	);

	// Set up the WordPress core custom background feature.
	add_theme_support(
		'custom-background',
		apply_filters(
			'mi_tema_personalizado_custom_background_args',
			array(
				'default-color' => 'ffffff',
				'default-image' => '',
			)
		)
	);

	// Add theme support for selective refresh for widgets.
	add_theme_support( 'customize-selective-refresh-widgets' );

	/**
	 * Add support for core custom logo.
	 *
	 * @link https://codex.wordpress.org/Theme_Logo
	 */
	add_theme_support(
		'custom-logo',
		array(
			'height'      => 250,
			'width'       => 250,
			'flex-width'  => true,
			'flex-height' => true,
		)
	);
}
add_action( 'after_setup_theme', 'mi_tema_personalizado_setup' );

/**
 * Set the content width in pixels, based on the theme's design and stylesheet.
 *
 * Priority 0 to make it available to lower priority callbacks.
 *
 * @global int $content_width
 */
function mi_tema_personalizado_content_width() {
	$GLOBALS['content_width'] = apply_filters( 'mi_tema_personalizado_content_width', 640 );
}
add_action( 'after_setup_theme', 'mi_tema_personalizado_content_width', 0 );

/**
 * Register widget area.
 *
 * @link https://developer.wordpress.org/themes/functionality/sidebars/#registering-a-sidebar
 */
function mi_tema_personalizado_widgets_init() {
	register_sidebar(
		array(
			'name'          => esc_html__( 'Barra lateral', 'mi-tema-personalizado' ),
			'id'            => 'sidebar-1',
			'description'   => esc_html__( 'Añade widgets aquí.', 'mi-tema-personalizado' ),
			'before_widget' => '<section id="%1$s" class="widget %2$s">',
			'after_widget'  => '</section>',
			'before_title'  => '<h2 class="widget-title">',
			'after_title'   => '</h2>',
		)
	);
}
add_action( 'widgets_init', 'mi_tema_personalizado_widgets_init' );

/**
 * Enqueue scripts and styles.
 */
function mi_tema_personalizado_scripts() {
	wp_enqueue_style( 'mi-tema-personalizado-style', get_stylesheet_uri(), array(), _S_VERSION );
	wp_style_add_data( 'mi-tema-personalizado-style', 'rtl', 'replace' );

	wp_enqueue_script( 'mi-tema-personalizado-navigation', get_template_directory_uri() . '/js/navigation.js', array(), _S_VERSION, true );

	if ( is_singular() &amp;&amp; comments_open() &amp;&amp; get_option( 'thread_comments' ) ) {
		wp_enqueue_script( 'comment-reply' );
	}
}
add_action( 'wp_enqueue_scripts', 'mi_tema_personalizado_scripts' );
Este archivo es bastante extenso, así que vamos a explicar las partes más importantes:
  • _S_VERSION
    :
    Define una constante con el número de versión del tema. Se usa para el control de versiones de los archivos CSS y JS.
  • mi_tema_personalizado_setup()
    :
    Esta función se ejecuta después de que el tema se haya cargado (hook
    after_setup_theme
    ). Aquí es donde configuramos las características básicas del tema.
  • load_theme_textdomain()
    :
    Carga los archivos de traducción del tema.
  • add_theme_support()
    :
    Añade soporte para diversas características de WordPress, como:
    • automatic-feed-links
      : Añade enlaces a los feeds RSS en la etiqueta
      <head>
      .
    • title-tag
      : Permite que WordPress gestione la etiqueta
      <title>
      .
    • post-thumbnails
      : Habilita las imágenes destacadas para entradas y páginas.
    • html5
      : Permite usar etiquetas HTML5 en formularios de búsqueda, comentarios, etc.
    • custom-background
      : Permite personalizar el fondo del sitio.
    • customize-selective-refresh-widgets
      : Permite la actualización selectiva de widgets en el Personalizador.
    • custom-logo
      : Permite añadir un logo personalizado a través del Personalizador.
  • register_nav_menus()
    :
    Registra un menú de navegación llamado "menu-principal". Este es el menú que mostramos en
    header.php
    .
  • mi_tema_personalizado_content_width()
    :
    Establece el ancho máximo del contenido.
  • mi_tema_personalizado_widgets_init()
    :
    Registra una barra lateral llamada "sidebar-1". Esta es la barra lateral que mostramos en
    sidebar.php
    .
  • mi_tema_personalizado_scripts()
    :
    "Encola" (carga) las hojas de estilo y los scripts del tema.
    • wp_enqueue_style()
      :
      Carga la hoja de estilos principal (
      style.css
      ).
    • wp_style_add_data()
      :
      Añade soporte para estilos RTL (de derecha a izquierda).
    • wp_enqueue_script()
      :
      Carga un archivo JavaScript llamado
      navigation.js
      (lo crearemos más adelante). También carga el script
      comment-reply
      si estamos en una entrada individual, los comentarios están abiertos y los comentarios anidados están habilitados.
Crea una carpeta
/languages
dentro de tu tema. Más tarde, crearemos los archivos de traducción en esta carpeta. También crea un archivo
navigation.js
en blanco dentro de una carpeta
/js
en tu tema, lo usaremos después.

Creación de single.php (plantilla para entradas individuales)

El archivo
single.php
controla la visualización de las *entradas individuales* del blog. Cuando un visitante hace clic en el título de una entrada en la página de inicio o en una página de archivo, WordPress usa
single.php
para mostrar el contenido completo de esa entrada. Crea el archivo y añade lo siguiente:

<?php
/**
 * The template for displaying all single posts
 *
 * @link https://developer.wordpress.org/themes/basics/template-hierarchy/#single-post
 *
 * @package mi_tema_personalizado
 */

get_header();
?>

	<main id="primary" class="site-main">

		<?php
		while ( have_posts() ) :
			the_post();

			get_template_part( 'template-parts/content', get_post_type() );

			the_post_navigation(
				array(
					'prev_text' => '<span class="nav-subtitle">' . esc_html__( 'Previous:', 'mi-tema-personalizado' ) . '</span> <span class="nav-title">%title</span>',
					'next_text' => '<span class="nav-subtitle">' . esc_html__( 'Next:', 'mi-tema-personalizado' ) . '</span> <span class="nav-title">%title</span>',
				)
			);

			// If comments are open or we have at least one comment, load up the comment template.
			if ( comments_open() || get_comments_number() ) :
				comments_template();
			endif;

		endwhile; // End of the loop.
		?>

	</main><!-- #main -->

<?php
get_sidebar();
get_footer();
La estructura de
single.php
es muy similar a la de
index.php
. La principal diferencia radica en lo que hacemos dentro del Loop:
  • Incluimos, como en
    index.php
    , el
    template-parts/content
    , que mostrará el contenido.
  • the_post_navigation()
    : Esta función muestra enlaces a la entrada anterior y siguiente. Hemos personalizado el texto de los enlaces.
  • comments_open() || get_comments_number()
    :
    Comprueba si los comentarios están abiertos o si hay algún comentario.
  • comments_template()
    :
    Si los comentarios están abiertos o hay comentarios, se carga la plantilla de comentarios (
    comments.php
    ). La crearemos más adelante.

Creando page.php (plantilla para paginas)

Mientras que
single.php
se usa para las *entradas* individuales,
page.php
se usa para las *páginas* estáticas (como "Acerca de", "Contacto", etc.). Su estructura es similar a
single.php
y a
index.php
. Crea el archivo, y añade:

<?php
/**
 * The template for displaying all pages
 *
 * This is the template that displays all pages by default.
 * Please note that this is the WordPress construct of pages
 * and that other 'pages' on your WordPress site may use a
 * different template.
 *
 * @link https://developer.wordpress.org/themes/basics/template-hierarchy/
 *
 * @package mi_tema_personalizado
 */

get_header();
?>

	<main id="primary" class="site-main">

		<?php
		while ( have_posts() ) :
			the_post();

			get_template_part( 'template-parts/content', 'page' );

			// If comments are open or we have at least one comment, load up the comment template.
			if ( comments_open() || get_comments_number() ) :
				comments_template();
			endif;

		endwhile; // End of the loop.
		?>

	</main><!-- #main -->

<?php
get_sidebar();
get_footer();
  • La principal diferencia aquí es que usamos
    get_template_part( 'template-parts/content', 'page' )
    . Esto significa que crearemos un archivo llamado
    content-page.php
    dentro de la carpeta
    template-parts
    para mostrar el contenido de las páginas.
  • También se incluye la sección de comentarios, de forma similar a
    single.php
    .

Creando una plantilla personalizada para una pagina en especifico.

WordPress permite crear plantillas personalizadas que se pueden asignar a páginas específicas. Esto es útil si quieres que una página tenga un diseño o una funcionalidad diferente al resto de las páginas. Para crear una plantilla personalizada, crea un nuevo archivo PHP en la raíz de tu tema (por ejemplo,
mi-plantilla-personalizada.php
) y añade la siguiente cabecera:

<?php
/**
 * Template Name: Mi Plantilla Personalizada
 * Template Post Type: page
 *
 * @package mi_tema_personalizado
 */

get_header();
?>
    <main id="primary" class="site-main">
        <?php
        while ( have_posts() ) :
            the_post();

            ?>
            <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
                <header class="entry-header">
                    <?php the_title( '<h1 class="entry-title">', '</h1>' ); ?>
                </header><!-- .entry-header -->

                <?php mi_tema_personalizado_post_thumbnail(); ?>

                <div class="entry-content">
                    <?php
                    the_content();

                    wp_link_pages(
                        array(
                            'before' => '<div class="page-links">' . esc_html__( 'Pages:', 'mi-tema-personalizado' ),
                            'after'  => '</div>',
                        )
                    );
                    ?>
                </div><!-- .entry-content -->

                <?php if ( get_edit_post_link() ) : ?>
                    <footer class="entry-footer">
                        <?php
                        edit_post_link(
                            sprintf(
                                wp_kses(
                                    /* translators: %s: Name of current post. Only visible to screen readers */
                                    __( 'Edit <span class="screen-reader-text">%s</span>', 'mi-tema-personalizado' ),
                                    array(
                                        'span' => array(
                                            'class' => array(),
                                        ),
                                    )
                                ),
                                wp_kses_post( get_the_title() )
                            ),
                            '<span class="edit-link">',
                            '</span>'
                        );
                        ?>
                    </footer><!-- .entry-footer -->
                <?php endif; ?>
            </article><!-- #post-<?php the_ID(); ?> -->
            <?php

            // If comments are open or we have at least one comment, load up the comment template.
			if ( comments_open() || get_comments_number() ) :
				comments_template();
			endif;

        endwhile; // End of the loop.
        ?>

    </main><!-- #main -->

<?php
get_sidebar();
get_footer();
La línea clave aquí es
Template Name: Mi Plantilla Personalizada
. Esto es lo que le dice a WordPress que este archivo es una plantilla personalizada, y el nombre que aparecerá en el editor de páginas de WordPress. El
Template Post Type: page
indica que es para el tipo de post "página". Dentro del loop, puedes personalizar el código como desees. Este ejemplo muestra una estructura basica para una página. Ahora, cuando edites una página en WordPress, verás un desplegable llamado "Plantilla" (normalmente en la barra lateral derecha, en la sección "Atributos de página"). Ahí podrás seleccionar "Mi Plantilla Personalizada". Con estos archivos, ya has dado un gran paso en la creación de tu tema. Hemos cubierto los archivos esenciales para mostrar el encabezado, el pie de página, las entradas individuales, las páginas y cómo crear plantillas personalizadas.

El Loop de WordPress

El "Loop" de WordPress es, sin duda, uno de los conceptos más importantes y fundamentales en el desarrollo de temas. Es el mecanismo que WordPress utiliza para recorrer y mostrar el contenido (entradas, páginas, etc.) que coincide con la consulta actual. Entender el Loop es crucial para poder personalizar la forma en que se muestra tu contenido.

Entendiendo el Funcionamiento del Loop

El Loop es, en esencia, un bucle
while
de PHP que se ejecuta mientras haya entradas (o páginas, o cualquier otro tipo de contenido) que coincidan con la consulta actual. Dentro del Loop, WordPress pone a tu disposición una serie de funciones que te permiten acceder a los datos de la entrada actual (título, contenido, fecha, autor, etc.) y mostrarlos en tu plantilla. La estructura básica del Loop es la siguiente:

<?php
if ( have_posts() ) :
    while ( have_posts() ) : the_post();
        // Aquí va el código para mostrar el contenido de cada entrada.
    endwhile;
else :
    // Aquí va el código para mostrar si no hay entradas.
endif;
?>
Vamos a desglosar cada parte:
  • if ( have_posts() ) :
    :
    Esta es la condición inicial. La función
    have_posts()
    comprueba si hay entradas que coincidan con la consulta actual. Si hay al menos una entrada, la condición se evalúa como verdadera y se ejecuta el código dentro del
    if
    .
  • while ( have_posts() ) : the_post();
    :
    Este es el bucle en sí. La función
    have_posts()
    se vuelve a evaluar en cada iteración. Mientras siga habiendo entradas, el bucle continúa. La función
    the_post()
    es *crucial*. Prepara la entrada actual para que puedas acceder a sus datos con funciones como
    the_title()
    ,
    the_content()
    , etc. Sin
    the_post()
    , estas funciones no funcionarían correctamente.
  • // Aquí va el código para mostrar el contenido de cada entrada.
    :
    Dentro del bucle, puedes usar las funciones de WordPress para mostrar el contenido de la entrada actual.
  • endwhile;
    :
    Cierra el bucle
    while
    .
  • else :
    :
    Esta parte es opcional. Aquí puedes poner el código que se ejecutará si no hay entradas que coincidan con la consulta.
  • endif;
    :
    Cierra la condición
    if
    .

Implementación del Loop en index.php, single.php, page.php, etc.

Ya hemos visto el Loop en acción en los archivos
index.php
,
single.php
y
page.php
que creamos anteriormente. La estructura básica es la misma en todos ellos, pero lo que hacemos *dentro* del Loop puede variar. Por ejemplo, en
index.php
, normalmente mostramos un resumen de cada entrada (título, extracto, fecha, etc.), mientras que en
single.php
mostramos el contenido completo de la entrada. Veamos un ejemplo de cómo podríamos personalizar el Loop en
index.php
para mostrar un resumen de cada entrada:

<?php
if ( have_posts() ) :
    while ( have_posts() ) : the_post(); ?>

        <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
            <header class="entry-header">
                <?php the_title( sprintf( '<h2 class="entry-title"><a href="%s" rel="bookmark">', esc_url( get_permalink() ) ), '</a></h2>' ); ?>
                <?php if ( 'post' === get_post_type() ) : ?>
                    <div class="entry-meta">
                        <?php
                        //Función personalizada, se crea más adelante.
                        mi_tema_personalizado_posted_on();
                        mi_tema_personalizado_posted_by();
                        ?>
                    </div><!-- .entry-meta -->
                <?php endif; ?>
            </header><!-- .entry-header -->

            <?php mi_tema_personalizado_post_thumbnail(); ?>

            <div class="entry-summary">
                <?php the_excerpt(); ?>
            </div><!-- .entry-summary -->

            <footer class="entry-footer">
                 <?php mi_tema_personalizado_entry_footer(); ?>
             </footer>

        </article><!-- #post-<?php the_ID(); ?> -->

    <?php endwhile;

    the_posts_navigation();

else :

    get_template_part( 'template-parts/content', 'none' );

endif;
?>
En este código, usamos:
  • the_ID()
    :
    Obtiene el ID de la entrada actual.
  • post_class()
    :
    Añade clases CSS a la etiqueta
    <article>
    que describen la entrada.
  • the_title()
    :
    Muestra el título de la entrada. Lo hemos envuelto en un enlace (
    <a>
    ) que apunta a la URL de la entrada individual (
    get_permalink()
    ).
  • get_permalink()
    :
    Obtiene la URL permanente de la entrada actual.
  • get_post_type()
    :
    Obtiene el tipo de entrada (post, page, etc.).
  • the_excerpt()
    :
    Muestra un resumen de la entrada.
  • mi_tema_personalizado_posted_on()
    ,
    mi_tema_personalizado_posted_by()
    y
    mi_tema_personalizado_entry_footer()
    :
    Estas son *funciones personalizadas* que crearemos en
    functions.php
    para mostrar la fecha, el autor y los metadatos del footer de la entrada, respectivamente.
  • mi_tema_personalizado_post_thumbnail()
    :
    Función personalizada para mostrar la imagen destacada.
Ahora, vamos a crear esas funciones personalizadas en
functions.php
. Añade el siguiente código a tu archivo
functions.php
(dentro de la función de configuración del tema, o en un archivo incluido):

if ( ! function_exists( 'mi_tema_personalizado_posted_on' ) ) :
	/**
	 * Prints HTML with meta information for the current post-date/time.
	 */
	function mi_tema_personalizado_posted_on() {
		$time_string = '<time class="entry-date published updated" datetime="%1$s">%2$s</time>';
		if ( get_the_time( 'U' ) !== get_the_modified_time( 'U' ) ) {
			$time_string = '<time class="entry-date published" datetime="%1$s">%2$s</time><time class="updated" datetime="%3$s">%4$s</time>';
		}

		$time_string = sprintf(
			$time_string,
			esc_attr( get_the_date( DATE_W3C ) ),
			esc_html( get_the_date() ),
			esc_attr( get_the_modified_date( DATE_W3C ) ),
			esc_html( get_the_modified_date() )
		);

		$posted_on = sprintf(
			/* translators: %s: post date. */
			esc_html_x( 'Posted on %s', 'post date', 'mi-tema-personalizado' ),
			'<a href="' . esc_url( get_permalink() ) . '" rel="bookmark">' . $time_string . '</a>'
		);

		echo '<span class="posted-on">' . $posted_on . '</span>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped

	}
endif;

if ( ! function_exists( 'mi_tema_personalizado_posted_by' ) ) :
	/**
	 * Prints HTML with meta information for the current author.
	 */
	function mi_tema_personalizado_posted_by() {
		$byline = sprintf(
			/* translators: %s: post author. */
			esc_html_x( 'by %s', 'post author', 'mi-tema-personalizado' ),
			'<span class="author vcard"><a class="url fn n" href="' . esc_url( get_author_posts_url( get_the_author_meta( 'ID' ) ) ) . '">' . esc_html( get_the_author() ) . '</a></span>'
		);

		echo '<span class="byline"> ' . $byline . '</span>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped

	}
endif;

if ( ! function_exists( 'mi_tema_personalizado_entry_footer' ) ) :
    /**
     * Prints HTML with meta information for the categories, tags and comments.
     */
    function mi_tema_personalizado_entry_footer() {
        // Hide category and tag text for pages.
        if ( 'post' === get_post_type() ) {
            /* translators: used between list items, there is a space after the comma */
            $categories_list = get_the_category_list( esc_html__( ', ', 'mi-tema-personalizado' ) );
            if ( $categories_list ) {
                /* translators: 1: list of categories. */
                printf( '<span class="cat-links">' . esc_html__( 'Posted in %1$s', 'mi-tema-personalizado' ) . '</span>', $categories_list ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
            }

            /* translators: used between list items, there is a space after the comma */
            $tags_list = get_the_tag_list( '', esc_html_x( ', ', 'list item separator', 'mi-tema-personalizado' ) );
            if ( $tags_list ) {
                /* translators: 1: list of tags. */
                printf( '<span class="tags-links">' . esc_html__( 'Tagged %1$s', 'mi-tema-personalizado' ) . '</span>', $tags_list ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
            }
        }

        if ( ! is_single() &amp;&amp; ! post_password_required() &amp;&amp; ( comments_open() || get_comments_number() ) ) {
            echo '<span class="comments-link">';
            comments_popup_link(
                sprintf(
                    wp_kses(
                        /* translators: %s: post title */
                        __( 'Leave a Comment<span class="screen-reader-text"> on %s</span>', 'mi-tema-personalizado' ),
                        array(
                            'span' => array(
                                'class' => array(),
                            ),
                        )
                    ),
                    wp_kses_post( get_the_title() )
                )
            );
            echo '</span>';
        }

        edit_post_link(
            sprintf(
                wp_kses(
                    /* translators: %s: Name of current post. Only visible to screen readers */
                    __( 'Edit <span class="screen-reader-text">%s</span>', 'mi-tema-personalizado' ),
                    array(
                        'span' => array(
                            'class' => array(),
                        ),
                    )
                ),
                wp_kses_post( get_the_title() )
            ),
            '<span class="edit-link">',
            '</span>'
        );
    }
endif;

if ( ! function_exists( 'mi_tema_personalizado_post_thumbnail' ) ) :
	/**
	 * Displays an optional post thumbnail.
	 *
	 * Wraps the post thumbnail in an anchor element on index views, or a div
	 * element when on single views.
	 */
	function mi_tema_personalizado_post_thumbnail() {
		if ( post_password_required() || is_attachment() || ! has_post_thumbnail() ) {
			return;
		}

		if ( is_singular() ) :
			?>

			<div class="post-thumbnail">
				<?php the_post_thumbnail(); ?>
			</div><!-- .post-thumbnail -->

		<?php else : ?>

		<a class="post-thumbnail" href="<?php the_permalink(); ?>" aria-hidden="true" tabindex="-1">
			<?php
			the_post_thumbnail(
				'post-thumbnail',
				array(
					'alt' => the_title_attribute(
						array(
							'echo' => false,
						)
					),
				)
			);
			?>
		</a>

		<?php
		endif; // End is_singular().
	}
endif;
Estas funciones se encargan de:
  • mi_tema_personalizado_posted_on()
    :
    Mostrar la fecha de publicación de la entrada.
  • mi_tema_personalizado_posted_by()
    :
    Mostrar el autor de la entrada.
  • mi_tema_personalizado_entry_footer()
    :
    Mostrar las categorías, etiquetas y enlace a comentarios.
  • mi_tema_personalizado_post_thumbnail()
    :
    Muestra la imagen destacada, si la hay. Si estamos en una vista de archivo (como
    index.php
    ), la imagen se envuelve en un enlace a la entrada individual.
Además, crea en tu carpeta
template-parts
los archivos
content.php
,
content-page.php
y
content-none.php
: content.php:

<?php
/**
 * Template part for displaying posts
 *
 * @link https://developer.wordpress.org/themes/basics/template-hierarchy/
 *
 * @package mi_tema_personalizado
 */

?>

<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
	<header class="entry-header">
		<?php
		if ( is_singular() ) :
			the_title( '<h1 class="entry-title">', '</h1>' );
		else :
			the_title( '<h2 class="entry-title"><a href="' . esc_url( get_permalink() ) . '" rel="bookmark">', '</a></h2>' );
		endif;

		if ( 'post' === get_post_type() ) :
			?>
			<div class="entry-meta">
				<?php
				mi_tema_personalizado_posted_on();
				mi_tema_personalizado_posted_by();
				?>
			</div><!-- .entry-meta -->
		<?php endif; ?>
	</header><!-- .entry-header -->

	<?php mi_tema_personalizado_post_thumbnail(); ?>

	<div class="entry-content">
		<?php
		the_content(
			sprintf(
				wp_kses(
					/* translators: %s: Name of current post. Only visible to screen readers */
					__( 'Continue reading<span class="screen-reader-text"> "%s"</span>', 'mi-tema-personalizado' ),
					array(
						'span' => array(
							'class' => array(),
						),
					)
				),
				wp_kses_post( get_the_title() )
			)
		);

		wp_link_pages(
			array(
				'before' => '<div class="page-links">' . esc_html__( 'Pages:', 'mi-tema-personalizado' ),
				'after'  => '</div>',
			)
		);
		?>
	</div><!-- .entry-content -->

	<footer class="entry-footer">
		<?php mi_tema_personalizado_entry_footer(); ?>
	</footer><!-- .entry-footer -->
</article><!-- #post-<?php the_ID(); ?> -->
content-page.php:

<?php
/**
 * Template part for displaying page content in page.php
 *
 * @link https://developer.wordpress.org/themes/basics/template-hierarchy/
 *
 * @package mi_tema_personalizado
 */

?>

<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
	<header class="entry-header">
		<?php the_title( '<h1 class="entry-title">', '</h1>' ); ?>
	</header><!-- .entry-header -->

	<?php mi_tema_personalizado_post_thumbnail(); ?>

	<div class="entry-content">
		<?php
		the_content();

		wp_link_pages(
			array(
				'before' => '<div class="page-links">' . esc_html__( 'Pages:', 'mi-tema-personalizado' ),
				'after'  => '</div>',
			)
		);
		?>
	</div><!-- .entry-content -->

	<?php if ( get_edit_post_link() ) : ?>
		<footer class="entry-footer">
			<?php
			edit_post_link(
				sprintf(
					wp_kses(
						/* translators: %s: Name of current post. Only visible to screen readers */
						__( 'Edit <span class="screen-reader-text">%s</span>', 'mi-tema-personalizado' ),
						array(
							'span' => array(
								'class' => array(),
							),
						)
					),
					wp_kses_post( get_the_title() )
				),
				'<span class="edit-link">',
				'</span>'
			);
			?>
		</footer><!-- .entry-footer -->
	<?php endif; ?>
</article><!-- #post-<?php the_ID(); ?> -->
content-none.php:

<?php
/**
 * Template part for displaying a message that posts cannot be found
 *
 * @link https://developer.wordpress.org/themes/basics/template-hierarchy/
 *
 * @package mi_tema_personalizado
 */

?>

<section class="no-results not-found">
	<header class="page-header">
		<h1 class="page-title"><?php esc_html_e( 'Nothing Found', 'mi-tema-personalizado' ); ?></h1>
	</header><!-- .page-header -->

	<div class="page-content">
		<?php
		if ( is_home() &amp;&amp; current_user_can( 'publish_posts' ) ) :

			printf(
				'<p>' . wp_kses(
					/* translators: 1: link to WP admin new post page. */
					__( 'Ready to publish your first post? <a href="%1$s">Get started here</a>.', 'mi-tema-personalizado' ),
					array(
						'a' => array(
							'href' => array(),
						),
					)
				) . '</p>',
				esc_url( admin_url( 'post-new.php' ) )
			);

		elseif ( is_search() ) :
			?>

			<p><?php esc_html_e( 'Sorry, but nothing matched your search terms. Please try again with some different keywords.', 'mi-tema-personalizado' ); ?></p>
			<?php
			get_search_form();

		else :
			?>

			<p><?php esc_html_e( 'It seems we can’t find what you’re looking for. Perhaps searching can help.', 'mi-tema-personalizado' ); ?></p>
			<?php
			get_search_form();

		endif;
		?>
	</div><!-- .page-content -->
</section><!-- .no-results -->

Funciones Comunes dentro del Loop (the_title(), the_content(), the_permalink(), etc.)

Dentro del Loop, tienes a tu disposición una gran cantidad de funciones para mostrar información sobre la entrada actual. Aquí tienes algunas de las más comunes:
  • the_title()
    :
    Muestra el título de la entrada.
  • the_content()
    :
    Muestra el contenido completo de la entrada.
  • the_excerpt()
    :
    Muestra un resumen de la entrada.
  • the_permalink()
    :
    Muestra la URL permanente de la entrada.
  • the_ID()
    :
    Muestra el ID de la entrada.
  • the_author()
    :
    Muestra el nombre del autor de la entrada.
  • the_date()
    :
    Muestra la fecha de publicación de la entrada.
  • the_time()
    :
    Muestra la hora de publicación de la entrada.
  • the_category()
    :
    Muestra las categorías a las que pertenece la entrada.
  • the_tags()
    :
    Muestra las etiquetas de la entrada.
  • the_post_thumbnail()
    :
    Muestra la imagen destacada de la entrada.
  • get_permalink()
    : Devuelve la URL de la entrada, en lugar de mostrarla directamente. Es útil para usarla dentro de atributos
    href
    , por ejemplo.
Estas son solo algunas de las muchas funciones disponibles. Puedes encontrar una lista completa en la documentación de WordPress: https://developer.wordpress.org/reference/functions/ ¡Con esto, ya tienes un buen entendimiento del Loop de WordPress! Es una herramienta poderosa que te permitirá mostrar tu contenido de forma dinámica y flexible.

Incorporación de CSS y JavaScript

Ya tenemos la estructura básica de nuestro tema y el contenido mostrándose correctamente gracias al Loop. Ahora, vamos a darle estilo y añadir interactividad con CSS y JavaScript. WordPress ofrece un sistema robusto y seguro para incorporar estos archivos, llamado "enqueuing" (encolado).

Enqueue de Estilos y Scripts (wp_enqueue_scripts)

La forma correcta de añadir CSS y JavaScript a tu tema de WordPress *no* es simplemente poner etiquetas
<link>
y
<script>
directamente en tu
header.php
o
footer.php
. Esto puede causar problemas de compatibilidad con plugins y dificultar el control de versiones. En su lugar, debes usar las funciones
wp_enqueue_style()
y
wp_enqueue_script()
dentro de una función que se enganche al hook
wp_enqueue_scripts
. Esto asegura que tus archivos se carguen en el orden correcto y que no haya conflictos. Ya hemos visto un ejemplo de esto en nuestro archivo
functions.php
:

/**
 * Enqueue scripts and styles.
 */
function mi_tema_personalizado_scripts() {
	wp_enqueue_style( 'mi-tema-personalizado-style', get_stylesheet_uri(), array(), _S_VERSION );
	wp_style_add_data( 'mi-tema-personalizado-style', 'rtl', 'replace' );

	wp_enqueue_script( 'mi-tema-personalizado-navigation', get_template_directory_uri() . '/js/navigation.js', array(), _S_VERSION, true );

	if ( is_singular() &amp;&amp; comments_open() &amp;&amp; get_option( 'thread_comments' ) ) {
		wp_enqueue_script( 'comment-reply' );
	}
}
add_action( 'wp_enqueue_scripts', 'mi_tema_personalizado_scripts' );
Vamos a desglosar cada función:
  • wp_enqueue_style( $handle, $src, $deps, $ver, $media )
    :
    • $handle
      :
      Un identificador único para tu hoja de estilos (por ejemplo, 'mi-tema-personalizado-style').
    • $src
      :
      La URL de tu hoja de estilos.
      get_stylesheet_uri()
      devuelve la URL de la hoja de estilos principal de tu tema (
      style.css
      ).
    • $deps
      :
      Un array de dependencias. Si tu hoja de estilos depende de otra hoja de estilos (por ejemplo, una hoja de estilos de un plugin), puedes especificar su identificador aquí. WordPress se asegurará de que las dependencias se carguen antes que tu hoja de estilos.
    • $ver
      :
      El número de versión de tu hoja de estilos. Es útil para el control de versiones y para evitar problemas de caché. Hemos definido una constante
      _S_VERSION
      en
      functions.php
      para esto.
    • $media
      :
      El tipo de medio para el que se aplica esta hoja de estilos (por ejemplo, 'all', 'screen', 'print'). Por defecto es 'all'.
  • wp_style_add_data( 'mi-tema-personalizado-style', 'rtl', 'replace' )
    :
    Añade soporte para estilos RTL, si el idioma del sitio es RTL, reemplaza la hoja de estilos principal por una versión RTL.
  • wp_enqueue_script( $handle, $src, $deps, $ver, $in_footer )
    :
    • $handle
      :
      Un identificador único para tu script.
    • $src
      :
      La URL de tu script.
      get_template_directory_uri()
      devuelve la URL del directorio de tu tema.
    • $deps
      :
      Un array de dependencias. Si tu script depende de otro script (por ejemplo, jQuery), puedes especificar su identificador aquí.
    • $ver
      :
      El número de versión de tu script.
    • $in_footer
      :
      Un valor booleano que indica si el script debe cargarse en el pie de página (
      true
      ) o en el encabezado (
      false
      ). Por defecto es
      false
      . Es una buena práctica cargar los scripts en el pie de página para mejorar el rendimiento de tu sitio, a menos que sea estrictamente necesario que se carguen en el encabezado.
  • if ( is_singular() &amp;&amp; comments_open() &amp;&amp; get_option( 'thread_comments' ) ) { wp_enqueue_script( 'comment-reply' ); }
    :
    Esta línea carga el script
    comment-reply
    de WordPress, que se encarga de la funcionalidad de responder a comentarios anidados. Solo se carga si estamos en una entrada individual (
    is_singular()
    ), los comentarios están abiertos (
    comments_open()
    ) y los comentarios anidados están habilitados (
    get_option( 'thread_comments' )
    ).
  • add_action( 'wp_enqueue_scripts', 'mi_tema_personalizado_scripts' );
    :
    Engancha nuestra función
    mi_tema_personalizado_scripts
    al hook
    wp_enqueue_scripts
    . Esto le dice a WordPress que ejecute nuestra función cuando sea el momento de cargar los estilos y scripts.
Vamos a añadir un archivo javascript, para ello creamos el archivo
/js/navigation.js
que ya hemos encolado y añadimos lo siguiente (Es un ejemplo basico para interacuar con el menú):

( function() {
    var container, button, menu, links, i, len;

    container = document.getElementById( 'site-navigation' );
    if ( ! container ) {
        return;
    }

    button = container.getElementsByTagName( 'button' )[0];
    if ( 'undefined' === typeof button ) {
        return;
    }

    menu = container.getElementsByTagName( 'ul' )[0];

    // Hide menu toggle button if menu is empty and return early.
    if ( 'undefined' === typeof menu ) {
        button.style.display = 'none';
        return;
    }

    menu.setAttribute( 'aria-expanded', 'false' );
    if ( -1 === menu.className.indexOf( 'nav-menu' ) ) {
        menu.className += ' nav-menu';
    }

    button.onclick = function() {
        if ( -1 !== container.className.indexOf( 'toggled' ) ) {
            container.className = container.className.replace( ' toggled', '' );
            button.setAttribute( 'aria-expanded', 'false' );
            menu.setAttribute( 'aria-expanded', 'false' );
        } else {
            container.className += ' toggled';
            button.setAttribute( 'aria-expanded', 'true' );
            menu.setAttribute( 'aria-expanded', 'true' );
        }
    };

    // Get all the link elements within the menu.
    links    = menu.getElementsByTagName( 'a' );

    // Each time a menu link is focused or blurred, toggle focus.
    for ( i = 0, len = links.length; i < len; i++ ) {
        links[i].addEventListener( 'focus', toggleFocus, true );
        links[i].addEventListener( 'blur', toggleFocus, true );
    }

    /**
     * Sets or removes .focus class on an element.
     */
    function toggleFocus() {
        var self = this;

        // Move up through the ancestors of the current link until we hit .nav-menu.
        while ( -1 === self.className.indexOf( 'nav-menu' ) ) {

            // On li elements toggle the class .focus.
            if ( 'li' === self.tagName.toLowerCase() ) {
                if ( -1 !== self.className.indexOf( 'focus' ) ) {
                    self.className = self.className.replace( ' focus', '' );
                } else {
                    self.className += ' focus';
                }
            }

            self = self.parentElement;
        }
    }

    /**
     * Toggles `focus` class to allow submenu access on tablets.
     */
    ( function( container ) {
        var touchStartFn, i,
            parentLink = container.querySelectorAll( '.menu-item-has-children > a, .page_item_has_children > a' );

        if ( 'ontouchstart' in window ) {
            touchStartFn = function( e ) {
                var menuItem = this.parentNode, i;

                if ( ! menuItem.classList.contains( 'focus' ) ) {
                    e.preventDefault();
                    for ( i = 0; i < menuItem.parentNode.children.length; ++i ) {
                        if ( menuItem === menuItem.parentNode.children[i] ) {
                            continue;
                        }
                        menuItem.parentNode.children[i].classList.remove( 'focus' );
                    }
                    menuItem.classList.add( 'focus' );
                } else {
                    menuItem.classList.remove( 'focus' );
                }
            };

            for ( i = 0; i < parentLink.length; ++i ) {
                parentLink[i].addEventListener( 'touchstart', touchStartFn, false );
            }
        }
    }( container ) );
} )();
Este archivo javascript añade la funcionalidad de menú hamburguesa, para poder desplegar el menu en dispositivos móviles.

Buenas Prácticas para la Organización de CSS y JS

A medida que tu tema crezca, es importante mantener tu CSS y JavaScript organizados. Aquí tienes algunas buenas prácticas:
  • Divide tu CSS en archivos más pequeños: En lugar de tener un solo archivo
    style.css
    gigante, puedes dividir tu CSS en archivos más pequeños y específicos (por ejemplo,
    header.css
    ,
    footer.css
    ,
    sidebar.css
    ,
    forms.css
    , etc.). Luego, puedes importar estos archivos en tu
    style.css
    principal usando la directiva
    @import
    (aunque esto puede afectar al rendimiento, es mejor encolarlos individualmente desde
    functions.php
    para tener más control). Otra opción es usar un preprocesador CSS como Sass, que te permite organizar tu CSS de forma más modular y eficiente.
  • Usa nombres de clases descriptivos y consistentes: Usa una convención de nombres para tus clases CSS (por ejemplo, BEM, SMACSS, OOCSS) para que tu código sea más fácil de entender y mantener.
  • Minifica tus archivos CSS y JS: La minificación reduce el tamaño de tus archivos CSS y JS eliminando espacios en blanco, comentarios y otros caracteres innecesarios. Esto mejora el tiempo de carga de tu sitio. Hay muchas herramientas online y plugins de WordPress que puedes usar para minificar tus archivos.
  • Usa un sistema de control de versiones (como Git): Esto te permitirá hacer un seguimiento de los cambios en tu código, volver a versiones anteriores si es necesario y colaborar con otros desarrolladores.
  • Comenta tu código: Añade comentarios a tu CSS y JavaScript para explicar lo que hace tu código. Esto te ayudará a ti y a otros desarrolladores a entender tu código en el futuro.
  • Considera usar un framework CSS: Un framework CSS (como Bootstrap, Tailwind CSS, Foundation) te proporciona una base sólida de estilos predefinidos que puedes usar para construir tu tema más rápidamente. Sin embargo, ten en cuenta que los frameworks pueden añadir peso a tu sitio si no los usas con cuidado.
Siguiendo estas buenas prácticas, podrás crear un tema de WordPress con un código limpio, organizado y eficiente.

Funciones Esenciales de WordPress para Templates

WordPress pone a tu disposición una gran cantidad de funciones que puedes usar en tus templates para acceder a datos, mostrar contenido, y en general, interactuar con el sistema. Ya hemos visto algunas de ellas (como
the_title()
,
the_content()
,
wp_enqueue_scripts()
, etc.), pero hay muchas más. En esta sección, vamos a explorar algunas de las funciones más esenciales y útiles para el desarrollo de temas.

Funciones de Encabezado (wp_head())

La función
wp_head()
es *fundamental* en cualquier tema de WordPress. Se coloca dentro de la etiqueta
<head>
de tu archivo
header.php
, y su función es insertar código esencial, como:
  • Enlaces a hojas de estilo (tanto del tema como de plugins).
  • Scripts (tanto del tema como de plugins).
  • Metadatos (como la etiqueta
    <title>
    , la descripción, etc.).
  • Etiquetas
    <link>
    para feeds RSS.
  • Y mucho más...
Muchos plugins *dependen* de
wp_head()
para funcionar correctamente. Si no la incluyes en tu tema, es muy probable que tengas problemas de compatibilidad y que algunas cosas no funcionen como esperas. Ejemplo (ya lo tenemos en nuestro
header.php
):

<head>
    <meta charset="<?php bloginfo( 'charset' ); ?>">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title><?php wp_title( '|', true, 'right' ); ?></title>
    <?php wp_head(); ?>
</head>
Simplemente coloca
<?php wp_head(); ?>
justo antes de la etiqueta de cierre
</head>
.

Funciones de Pie de Página (wp_footer())

La función
wp_footer()
es el equivalente a
wp_head()
, pero para el pie de página. Se coloca justo antes de la etiqueta de cierre
</body>
en tu archivo
footer.php
, y su función es insertar código, como:
  • Scripts que se cargan en el pie de página (para mejorar el rendimiento).
  • Código de seguimiento (como Google Analytics).
  • Barras de administración (si estás logueado como administrador).
  • Y mucho más...
Al igual que
wp_head()
, muchos plugins dependen de
wp_footer()
. No la olvides. Ejemplo (ya lo tenemos en nuestro
footer.php
):

<?php wp_footer(); ?>
</body>
</html>

Inclusión de Partes de Plantilla (get_header(), get_footer(), get_sidebar())

Estas funciones te permiten incluir partes de tu plantilla de forma modular. Ya las hemos usado en nuestros archivos:
  • get_header()
    :
    Incluye el archivo
    header.php
    .
  • get_footer()
    :
    Incluye el archivo
    footer.php
    .
  • get_sidebar()
    :
    Incluye el archivo
    sidebar.php
    .
Estas funciones hacen que tu código sea más limpio y fácil de mantener. En lugar de repetir el mismo código en cada plantilla, puedes simplemente incluir los archivos correspondientes. También existe
get_template_part()
que es similar, pero más flexible. Te permite incluir cualquier archivo de plantilla, no solo el encabezado, el pie de página o la barra lateral.

Funciones Condicionales (is_home(), is_single(), is_page(), etc.)

Las funciones condicionales te permiten comprobar qué tipo de página se está mostrando actualmente. Son muy útiles para mostrar contenido diferente o aplicar estilos CSS diferentes en función del contexto. Aquí tienes algunas de las funciones condicionales más comunes:
  • is_home()
    :
    Verifica si la página actual es la página de inicio (que muestra las últimas entradas).
  • is_front_page()
    :
    Verifica si la página actual es la página de inicio (independientemente de si muestra las últimas entradas o una página estática).
  • is_single()
    :
    Verifica si la página actual es una entrada individual.
  • is_page()
    :
    Verifica si la página actual es una página estática.
  • is_page_template()
    :
    Verifica si la página actual utiliza una plantilla de página específica.
  • is_singular()
    :
    Verifica si estamos mostrando un único elemento, ya sea post, página o custom post type.
  • is_archive()
    :
    Verifica si la página actual es una página de archivo (por ejemplo, una página de categoría, etiqueta, fecha, autor, etc.).
  • is_category()
    :
    Verifica si la página actual es una página de categoría.
  • is_tag()
    :
    Verifica si la página actual es una página de etiqueta.
  • is_author()
    :
    Verifica si la página actual es una página de autor.
  • is_search()
    :
    Verifica si la página actual es una página de resultados de búsqueda.
  • is_404()
    :
    Verifica si la página actual es una página de error 404 (página no encontrada).
  • comments_open()
    :
    Verifica si los comentarios están abiertos para la entrada actual.
  • pings_open()
    :
    Verifica si los pings (trackbacks y pingbacks) están abiertos para la entrada actual.
  • has_post_thumbnail()
    :
    Verifica si el post tiene una imagen destacada.
  • is_user_logged_in()
    :
    Verifica si el usuario actual ha iniciado sesión.
  • current_user_can( $capability )
    :
    Verifica si el usuario actual tiene un permiso determinado.
Puedes usar estas funciones condicionales en combinación con sentencias
if
,
elseif
y
else
para controlar el flujo de tu código y mostrar contenido diferente en diferentes situaciones. Ejemplo:

<?php
if ( is_home() ) {
    // Mostrar un mensaje especial en la página de inicio.
    echo '<p>¡Bienvenido a mi blog!</p>';
} elseif ( is_single() ) {
    // Mostrar el título de la entrada y el contenido completo.
    the_title( '<h1>', '</h1>' );
    the_content();
} elseif ( is_page() ) {
    // Mostrar el título de la página y el contenido.
    the_title( '<h1>', '</h1>' );
    the_content();
} else {
    // Mostrar un mensaje genérico.
    echo '<p>Contenido genérico</p>';
}
?>
Estas son solo algunas de las muchas funciones esenciales que WordPress ofrece. A medida que vayas desarrollando tu tema, te familiarizarás con muchas más. La clave es consultar la documentación de WordPress (https://developer.wordpress.org/reference/) siempre que necesites hacer algo específico.

Creación de Áreas de Widgets

Los widgets son pequeños bloques de contenido que puedes añadir a áreas específicas de tu tema, como la barra lateral, el pie de página, etc. Son una forma fácil de añadir funcionalidad a tu sitio sin tener que escribir código. WordPress incluye una serie de widgets predefinidos (como "Entradas recientes", "Comentarios recientes", "Buscar", "Categorías", etc.), y muchos plugins añaden sus propios widgets. Para poder usar widgets en tu tema, necesitas crear "áreas de widgets" (también llamadas "sidebars", aunque no se limitan a las barras laterales). Estas áreas son como contenedores donde los usuarios pueden arrastrar y soltar widgets desde el panel de administración de WordPress (Apariencia > Widgets).

Registro de Áreas de Widgets (register_sidebar())

Para registrar un área de widgets, debes usar la función
register_sidebar()
dentro de una función que se enganche al hook
widgets_init
. Ya hemos visto un ejemplo de esto en nuestro archivo
functions.php
:

/**
 * Register widget area.
 *
 * @link https://developer.wordpress.org/themes/functionality/sidebars/#registering-a-sidebar
 */
function mi_tema_personalizado_widgets_init() {
	register_sidebar(
		array(
			'name'          => esc_html__( 'Barra lateral', 'mi-tema-personalizado' ),
			'id'            => 'sidebar-1',
			'description'   => esc_html__( 'Añade widgets aquí.', 'mi-tema-personalizado' ),
			'before_widget' => '<section id="%1$s" class="widget %2$s">',
			'after_widget'  => '</section>',
			'before_title'  => '<h2 class="widget-title">',
			'after_title'   => '</h2>',
		)
	);
}
add_action( 'widgets_init', 'mi_tema_personalizado_widgets_init' );
Vamos a desglosar los parámetros de
register_sidebar()
:
  • name
    :
    El nombre del área de widgets (que se mostrará en el panel de administración).
  • id
    :
    Un identificador único para el área de widgets. Debe ser en minúsculas y sin espacios (usa guiones bajos o guiones).
  • description
    :
    Una descripción del área de widgets (que se mostrará en el panel de administración).
  • before_widget
    :
    El código HTML que se insertará *antes* de cada widget.
    %1$s
    se reemplaza por el ID del widget, y
    %2$s
    se reemplaza por las clases CSS del widget.
  • after_widget
    :
    El código HTML que se insertará *después* de cada widget.
  • before_title
    :
    El código HTML que se insertará *antes* del título de cada widget.
  • after_title
    :
    El código HTML que se insertará *después* del título de cada widget.
Puedes registrar tantas áreas de widgets como necesites. Por ejemplo, podrías registrar un área para la barra lateral, otra para el pie de página, otra para el encabezado, etc. Ejemplo, vamos a registrar un area de widget para el footer, añadimos al function.php:

function mi_tema_personalizado_widgets_init() {
	register_sidebar(
		array(
			'name'          => esc_html__( 'Barra lateral', 'mi-tema-personalizado' ),
			'id'            => 'sidebar-1',
			'description'   => esc_html__( 'Añade widgets aquí.', 'mi-tema-personalizado' ),
			'before_widget' => '<section id="%1$s" class="widget %2$s">',
			'after_widget'  => '</section>',
			'before_title'  => '<h2 class="widget-title">',
			'after_title'   => '</h2>',
		)
	);
    register_sidebar(
        array(
            'name'          => esc_html__( 'Footer', 'mi-tema-personalizado' ),
            'id'            => 'footer-1',
            'description'   => esc_html__( 'Añade widgets aquí para el footer.', 'mi-tema-personalizado' ),
            'before_widget' => '<section id="%1$s" class="widget %2$s">',
            'after_widget'  => '</section>',
            'before_title'  => '<h2 class="widget-title">',
            'after_title'   => '</h2>',
        )
    );
}
add_action( 'widgets_init', 'mi_tema_personalizado_widgets_init' );

Visualización de Widgets en el Template (dynamic_sidebar())

Una vez que hayas registrado un área de widgets, necesitas mostrarla en tu plantilla. Para ello, debes usar la función
dynamic_sidebar()
, pasando como parámetro el ID del área de widgets que quieres mostrar. Ya hemos visto un ejemplo de esto en nuestro archivo
sidebar.php
:

<?php
if ( ! is_active_sidebar( 'sidebar-1' ) ) {
	return;
}
?>

<aside id="secondary" class="widget-area">
	<?php dynamic_sidebar( 'sidebar-1' ); ?>
</aside><!-- #secondary -->
  • is_active_sidebar( 'sidebar-1' )
    :
    Comprueba si hay algún widget activo en ese area.
  • dynamic_sidebar( 'sidebar-1' )
    :
    Muestra los widgets.
Ahora, si vas al panel de administración de WordPress (Apariencia > Widgets), deberías ver tu área de widgets ("Barra lateral"). Puedes arrastrar y soltar widgets en esta área, y se mostrarán en tu sitio donde hayas colocado la función
dynamic_sidebar()
. Para mostrar el area de widget del footer, debemos añadir al archivo
footer.php
lo siguiente:

    </div><!-- #content -->

<footer id="colophon" class="site-footer">

<?php
if ( is_active_sidebar( 'footer-1' ) ) : ?>
    <div class="widget-area-footer">
        <?php dynamic_sidebar( 'footer-1' ); ?>
    </div>
<?php endif; ?>

    <div class="site-info">
        <a href="<?php echo esc_url( __( 'https://wordpress.org/', 'mi-tema-personalizado' ) ); ?>">
            <?php
            /* translators: %s: CMS name, i.e. WordPress. */
            printf( esc_html__( 'Proudly powered by %s', 'mi-tema-personalizado' ), 'WordPress' );
            ?>
        </a>
        <span class="sep"> | </span>
            <?php
            /* translators: 1: Theme name, 2: Theme author. */
            printf( esc_html__( 'Theme: %1$s by %2$s.', 'mi-tema-personalizado' ), 'mi-tema-personalizado', '<a href="https://example.com/">Tu Nombre</a>' );
            ?>
    </div><!-- .site-info -->
</footer><!-- #colophon -->

<?php wp_footer(); ?>

</body>
</html>
Hemos añadido el condicional
if ( is_active_sidebar( 'footer-1' ) )
y el
dynamic_sidebar( 'footer-1' )
dentro de un div. ¡Y eso es todo! Con
register_sidebar()
y
dynamic_sidebar()
, puedes crear áreas de widgets personalizadas en tu tema y permitir que los usuarios añadan contenido dinámico a tu sitio de forma fácil e intuitiva.

Personalización del Tema con el Personalizador de WordPress

El Personalizador de WordPress es una herramienta poderosa que permite a los usuarios personalizar la apariencia de su sitio web en tiempo real, sin tener que tocar el código. Puedes añadir opciones al Personalizador para permitir que los usuarios cambien colores, fuentes, imágenes, textos, y mucho más.

Añadiendo Opciones al Personalizador (add_setting(), add_control())

Para añadir opciones al Personalizador, necesitas usar dos funciones principales:
add_setting()
y
add_control()
. Estas funciones se usan dentro de una función que se engancha al hook
customize_register
. Vamos a crear un ejemplo práctico. Vamos a añadir una opción para que los usuarios puedan cambiar el color de fondo del encabezado. Añade el siguiente código a tu archivo
functions.php
:

/**
 * Add customizer settings and controls.
 * @param WP_Customize_Manager $wp_customize Theme Customizer object.
 */
function mi_tema_personalizado_customize_register( $wp_customize ) {

    // Añade una sección para las opciones de color.
    $wp_customize->add_section( 'mi_tema_personalizado_colors', array(
        'title'    => __( 'Colores', 'mi-tema-personalizado' ),
        'priority' => 30, // La prioridad determina el orden en el que se muestran las secciones.
    ) );

    // Añade una configuración para el color de fondo del encabezado.
    $wp_customize->add_setting( 'header_background_color', array(
        'default'           => '#ffffff', // Valor por defecto.
        'sanitize_callback' => 'sanitize_hex_color', // Función de sanitización.
        'transport'         => 'refresh', // Cómo se actualiza la vista previa ('refresh' o 'postMessage').
    ) );

    // Añade un control para el color de fondo del encabezado.
    $wp_customize->add_control( new WP_Customize_Color_Control( $wp_customize, 'header_background_color', array(
        'label'    => __( 'Color de Fondo del Encabezado', 'mi-tema-personalizado' ),
        'section'  => 'mi_tema_personalizado_colors', // La sección a la que pertenece este control.
        'settings' => 'header_background_color', // La configuración a la que está vinculado este control.
    ) ) );
}
add_action( 'customize_register', 'mi_tema_personalizado_customize_register' );
Vamos a desglosar este código:
  • mi_tema_personalizado_customize_register( $wp_customize )
    :
    Esta es la función que se ejecutará cuando se cargue el Personalizador. Recibe un objeto
    $wp_customize
    como parámetro, que es el que usaremos para añadir nuestras opciones.
  • $wp_customize->add_section( 'mi_tema_personalizado_colors', array(...) )
    :
    Añade una *sección* al Personalizador. Las secciones agrupan controles relacionados.
    • 'mi_tema_personalizado_colors'
      : El ID único de la sección.
    • 'title'
      : El título de la sección (que se mostrará en el Personalizador).
    • 'priority'
      : La prioridad de la sección (un número que determina su orden).
  • $wp_customize->add_setting( 'header_background_color', array(...) )
    :
    Añade una *configuración* (setting). Una configuración representa un valor que se puede personalizar.
    • 'header_background_color'
      : El ID único de la configuración.
    • 'default'
      : El valor por defecto de la configuración.
    • 'sanitize_callback'
      : Una función que se usa para "sanitizar" el valor de la configuración antes de guardarlo en la base de datos. En este caso, usamos
      sanitize_hex_color
      , que se asegura de que el valor sea un código de color hexadecimal válido.
    • 'transport'
      : Determina cómo se actualiza la vista previa cuando se cambia el valor de la configuración.
      'refresh'
      recarga la página, mientras que
      'postMessage'
      usa JavaScript para actualizar la vista previa sin recargarla (es más rápido, pero requiere que escribas código JavaScript para manejar la actualización).
  • $wp_customize->add_control( new WP_Customize_Color_Control( $wp_customize, 'header_background_color', array(...) ) )
    :
    Añade un *control* al Personalizador. Un control es el elemento de la interfaz de usuario que permite al usuario interactuar con una configuración (por ejemplo, un campo de texto, un selector de color, una casilla de verificación, etc.).
    • new WP_Customize_Color_Control()
      : Crea un nuevo control de tipo "selector de color". WordPress tiene muchos tipos de controles predefinidos (
      WP_Customize_Control
      ,
      WP_Customize_Image_Control
      ,
      WP_Customize_Upload_Control
      , etc.).
    • $wp_customize
      : El objeto del Personalizador.
    • 'header_background_color'
      : El ID del control.
    • 'label'
      : La etiqueta del control (que se mostrará en el Personalizador).
    • 'section'
      : El ID de la sección a la que pertenece este control.
    • 'settings'
      : El ID de la configuración a la que está vinculado este control.
  • add_action( 'customize_register', 'mi_tema_personalizado_customize_register' )
    :
    Engancha nuestra función al hook
    customize_register
    .

Mostrando las Opciones Personalizadas en el Template

Una vez que hayas añadido una configuración al Personalizador, necesitas usar su valor en tu plantilla. Para ello, debes usar la función
get_theme_mod()
, pasando como parámetro el ID de la configuración. Para mostrar el color de fondo del encabezado que hemos definido en el Personalizador, vamos a modificar nuestro archivo
header.php
. Vamos a añadir un estilo en línea a la etiqueta
<header>
:

<header id="masthead" class="site-header" style="background-color: <?php echo get_theme_mod( 'header_background_color', '#ffffff' ); ?>;">
Explicación:
  • get_theme_mod( 'header_background_color', '#ffffff' )
    :
    Obtiene el valor de la configuración
    'header_background_color'
    . El segundo parámetro (
    '#ffffff'
    ) es el valor por defecto que se usará si la configuración no tiene ningún valor (por ejemplo, la primera vez que se carga el tema).
¡Y eso es todo! Ahora, si vas al Personalizador de WordPress (Apariencia > Personalizar), deberías ver una sección llamada "Colores", y dentro de ella, un control llamado "Color de Fondo del Encabezado". Puedes cambiar el color, y verás cómo se actualiza la vista previa en tiempo real. Este es solo un ejemplo básico. Puedes añadir muchas más opciones al Personalizador para permitir que los usuarios personalicen casi cualquier aspecto de tu tema. Puedes añadir opciones para:
  • Cambiar las fuentes (tipografía).
  • Subir un logo personalizado.
  • Mostrar u ocultar elementos (como la barra lateral, el título del sitio, la descripción, etc.).
  • Añadir texto personalizado (como un mensaje de bienvenida, información de contacto, etc.).
  • Y mucho más...
Consulta la documentación de WordPress para obtener más información sobre el Personalizador y los diferentes tipos de controles que puedes usar: https://developer.wordpress.org/themes/customize-api/

Internacionalización y Localización (i18n y l10n)

La internacionalización (i18n) y la localización (l10n) son procesos que permiten que tu tema de WordPress sea traducido a diferentes idiomas. Es una buena práctica preparar tu tema para la traducción, incluso si no planeas traducirlo tú mismo. Esto facilitará que otros usuarios traduzcan tu tema si lo desean. La internacionalización es el proceso de preparar tu código para que pueda ser traducido. Esto implica usar funciones especiales de WordPress para envolver las cadenas de texto que se mostrarán en el sitio web. La localización es el proceso de traducir las cadenas de texto a un idioma específico.

Preparación del Tema para la Traducción

Para preparar tu tema para la traducción, debes seguir estos pasos:
  1. Define el dominio de texto (Text Domain): El dominio de texto es un identificador único para tu tema. Se usa para asociar las cadenas de texto traducibles con tu tema. Ya lo definimos en la cabecera de nuestro archivo
    style.css
    :
    
    /*
    Text Domain: mi-tema-personalizado
    */
            
    El dominio de texto debe coincidir con el nombre de la carpeta de tu tema (sin espacios ni caracteres especiales).
  2. Carga el dominio de texto: Debes cargar el dominio de texto en tu archivo
    functions.php
    . Ya lo hicimos en la función
    mi_tema_personalizado_setup()
    :
    
    load_theme_textdomain( 'mi-tema-personalizado', get_template_directory() . '/languages' );
            
    Esto le dice a WordPress que busque los archivos de traducción en la carpeta
    /languages
    dentro de tu tema.
  3. Usa funciones de traducción: Debes envolver todas las cadenas de texto que se mostrarán en el sitio web con funciones de traducción de WordPress. Las funciones más comunes son:
    • __()
      :
      Devuelve la traducción de una cadena de texto.
      
      <?php echo __( 'Hola Mundo', 'mi-tema-personalizado' ); ?>
                      
    • _e()
      :
      Muestra la traducción de una cadena de texto (similar a
      echo __()
      ).
      
      <?php _e( 'Hola Mundo', 'mi-tema-personalizado' ); ?>
                      
    • esc_html__()
      :
      Devuelve la traducción de una cadena de texto, y la "escapa" para que sea segura para mostrar en HTML.
      
      <?php echo esc_html__( 'Hola Mundo', 'mi-tema-personalizado' ); ?>
                      
    • esc_html_e()
      :
      Muestra la traducción de una cadena de texto, y la "escapa" para que sea segura.
      
      <?php esc_html_e( 'Hola Mundo', 'mi-tema-personalizado' ); ?>
                      
    • esc_attr__()
      :
      Devuelve la traducción de una cadena, y la "escapa" para usarla en atributos HTML.
      
      <a title="<?php esc_attr_e( 'Enlace de ejemplo', 'mi-tema-personalizado' ); ?>">...</a>
                      
    • esc_attr_e()
      :
      Muestra la traducción de una cadena, y la "escapa" para atributos.
    • printf()
      y
      sprintf()
      :
      Se usan para mostrar cadenas de texto que contienen variables. Debes usar funciones de traducción dentro de
      printf()
      o
      sprintf()
      .
      
      <?php printf( __( 'Bienvenido, %s', 'mi-tema-personalizado' ), $username ); ?>
                      
      
      $saludo = sprintf( __( 'Bienvenido, %s', 'mi-tema-personalizado' ), $username );
      echo $saludo;
                      

Uso de Funciones de Traducción

Veamos algunos ejemplos de cómo usar las funciones de traducción en diferentes situaciones: Texto simple:

<p><?php _e( 'Este es un texto de ejemplo.', 'mi-tema-personalizado' ); ?></p>
Texto con HTML:

<h1><?php esc_html_e( 'Título de la página', 'mi-tema-personalizado' ); ?></h1>
Texto en atributos HTML:

<a href="#" title="<?php esc_attr_e( 'Enlace de ejemplo', 'mi-tema-personalizado' ); ?>"><?php esc_html_e( 'Haz clic aquí', 'mi-tema-personalizado' ); ?></a>
Texto con variables:

<?php
$nombre = 'Juan';
printf(
    /* translators: %s is the user's name. */
    __( 'Hola, %s', 'mi-tema-personalizado' ),
    $nombre
);
?>
Nota:
  • /* translators: */
    : Esto permite añadir contexto para los traductores.
Creación de archivos de traducción: Una vez que hayas preparado tu tema para la traducción, necesitas crear los archivos de traducción. Los archivos de traducción son archivos de texto con la extensión
.po
(Portable Object) y
.mo
(Machine Object).
  1. Genera un archivo POT (Portable Object Template): El archivo POT es una plantilla que contiene todas las cadenas de texto traducibles de tu tema. Puedes generar un archivo POT usando herramientas como:
    • WP-CLI: Si tienes WP-CLI instalado, puedes usar el comando
      wp i18n make-pot
      . Ejecuta este comando desde la carpeta de tu tema:
      
      wp i18n make-pot . languages/mi-tema-personalizado.pot
                      
      Esto generará un archivo llamado
      mi-tema-personalizado.pot
      en la carpeta
      /languages
      .
    • Poedit: Poedit es un editor de traducciones gratuito y de código abierto que puedes usar para generar archivos POT, editar archivos PO y compilar archivos MO.
    • Plugin Loco Translate: Loco Translate es un plugin de WordPress que te permite gestionar las traducciones directamente desde el panel de administración.
  2. Crea archivos PO para cada idioma: A partir del archivo POT, debes crear un archivo PO para cada idioma al que quieras traducir tu tema. Por ejemplo, para traducir tu tema al español, deberías crear un archivo llamado
    es_ES.po
    . Puedes usar Poedit o Loco Translate para crear y editar archivos PO.
  3. Traduce las cadenas de texto: Abre el archivo PO con Poedit o Loco Translate, y traduce cada cadena de texto.
  4. Compila los archivos MO: Una vez que hayas traducido las cadenas de texto, debes compilar el archivo PO en un archivo MO. El archivo MO es el que WordPress usa para cargar las traducciones. Poedit y Loco Translate compilan automáticamente los archivos MO cuando guardas los archivos PO. El archivo .mo debe tener el mismo nombre que el .po (ej:
    es_ES.mo
    ).
  5. Coloca los archivos .po y .mo en la carpeta languages.
Una vez que hayas creado los archivos de traducción, WordPress los cargará automáticamente en función del idioma configurado en los ajustes generales de WordPress (Ajustes > Generales > Idioma del sitio). Siguiendo estos pasos, tu tema estará listo para ser traducido a cualquier idioma, lo que lo hará accesible a un público mucho más amplio.

Pruebas y Depuración

Una vez que hayas terminado de desarrollar tu tema (o incluso durante el proceso de desarrollo), es crucial realizar pruebas exhaustivas y depurar cualquier error que encuentres. Un tema bien probado y libre de errores garantizará una mejor experiencia para los usuarios y evitará problemas de compatibilidad.

Uso de plugins de desarrollo

Existen varios plugins de WordPress que pueden ayudarte con las pruebas y la depuración:
  • Debug Bar: Añade una barra de herramientas en la parte superior de tu sitio (cuando estás logueado como administrador) que muestra información útil para la depuración, como consultas a la base de datos, errores de PHP, peticiones HTTP, etc. https://wordpress.org/plugins/debug-bar/
  • Query Monitor: Similar a Debug Bar, pero con una interfaz más moderna y más opciones de depuración. Te permite ver consultas a la base de datos, errores de PHP, scripts y estilos encolados, peticiones HTTP, hooks de WordPress, y mucho más. Es una herramienta muy completa. https://wordpress.org/plugins/query-monitor/
  • Theme Check: Verifica tu tema contra los estándares de codificación de WordPress y las mejores prácticas. Te ayuda a identificar posibles problemas y a asegurarte de que tu tema cumple con los requisitos para ser publicado en el directorio de temas de WordPress.org. https://wordpress.org/plugins/theme-check/
  • Developer: Un plugin que te ayuda a configurar un entorno de desarrollo de WordPress. Te recomienda otros plugins útiles para el desarrollo, como los mencionados anteriormente. https://wordpress.org/plugins/developer/
  • Log Deprecated Notices: Registra el uso de funciones, argumentos de funciones y archivos obsoletos de WordPress. Te ayuda a identificar código que necesita ser actualizado para mantener la compatibilidad con futuras versiones de WordPress. https://wordpress.org/plugins/log-deprecated-notices/
Instala y activa estos plugins en tu entorno de desarrollo local. Te proporcionarán información valiosa y te ayudarán a encontrar y corregir errores más rápidamente.

Revisión del código

Además de usar plugins, es importante revisar tu código manualmente para asegurarte de que:
  • Sigue los estándares de codificación de WordPress: WordPress tiene una guía de estilo detallada que debes seguir. Esto hará que tu código sea más legible, mantenible y compatible. https://developer.wordpress.org/coding-standards/
  • Está bien comentado: Añade comentarios a tu código para explicar lo que hace. Esto te ayudará a ti y a otros desarrolladores a entender tu código en el futuro.
  • Es eficiente: Evita consultas a la base de datos innecesarias, bucles anidados complejos, y código redundante. Un código eficiente mejorará el rendimiento de tu tema.
  • Es seguro: "Escapa" (sanitize) todos los datos que provienen de fuentes externas (como entradas de formularios, variables de URL, etc.) para evitar vulnerabilidades de seguridad. Usa funciones como
    esc_html()
    ,
    esc_attr()
    ,
    esc_url()
    ,
    sanitize_text_field()
    , etc.
  • Es compatible con diferentes navegadores y dispositivos: Prueba tu tema en diferentes navegadores (Chrome, Firefox, Safari, Edge) y dispositivos (ordenadores de escritorio, tablets, smartphones) para asegurarte de que se ve y funciona correctamente en todos ellos. Puedes usar herramientas como BrowserStack o LambdaTest para facilitar las pruebas en diferentes plataformas.
  • Es accesible: Asegúrate de que tu tema es accesible para personas con discapacidades. Usa etiquetas HTML semánticas, proporciona texto alternativo para las imágenes, usa colores con suficiente contraste, etc. Puedes usar herramientas como WAVE (Web Accessibility Evaluation Tool) para verificar la accesibilidad de tu sitio.
  • Está validado: Valida tu HTML y CSS usando el validador del W3C: https://validator.w3.org/ (HTML) https://jigsaw.w3.org/css-validator/ (CSS)
Activa el modo debug de WordPress. Para ello, edita el archivo
wp-config.php
de tu instalación de WordPress y busca la línea que define la constante
WP_DEBUG
. Cámbiala a
true
:

define( 'WP_DEBUG', true );
Esto hará que WordPress muestre errores, advertencias y avisos de PHP en tu sitio. Es *muy* importante que *no* hagas esto en un sitio en producción, ya que podría exponer información sensible a los visitantes. Usa
WP_DEBUG
solo en tu entorno de desarrollo local. También es recomendable activar
WP_DEBUG_LOG
y
WP_DEBUG_DISPLAY
:

define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );
  • WP_DEBUG_LOG
    : Guarda todos los errores en un archivo llamado
    debug.log
    dentro de la carpeta
    wp-content
    .
  • WP_DEBUG_DISPLAY
    : Controla si los errores se muestran o no en el HTML de las páginas. En este caso, lo hemos establecido en
    false
    para que los errores no se muestren en el sitio, pero sí se guarden en el archivo de registro.
Realizar pruebas exhaustivas y depurar tu código es un paso esencial en el desarrollo de cualquier tema de WordPress. Te ayudará a crear un tema de alta calidad que sea estable, seguro y fácil de usar.

Empaquetado y Distribución del Tema

Una vez que hayas terminado de desarrollar y probar tu tema, es hora de empaquetarlo para distribuirlo. Ya sea que planees compartirlo con otros, subirlo al directorio de temas de WordPress.org, o simplemente usarlo en tus propios sitios, necesitas crear un archivo ZIP que contenga todos los archivos necesarios. Pasos para empaquetar tu tema:
  1. Asegúrate de que tienes todos los archivos esenciales:
    • style.css
      (con la cabecera del tema).
    • index.php
      .
    • header.php
      .
    • footer.php
      .
    • functions.php
      .
    • screenshot.png
      (una imagen de captura de pantalla de tu tema, de 1200x900 píxeles).
    • Cualquier otro archivo de plantilla que hayas creado (
      single.php
      ,
      page.php
      ,
      sidebar.php
      ,
      archive.php
      , etc.).
    • Carpetas
      /js
      ,
      /css
      ,
      /images
      ,
      /languages
      ,
      /template-parts
      ,
      /inc
      (si las tienes).
  2. Elimina archivos innecesarios:
    • Archivos de configuración de tu editor de código (como
      .vscode
      ,
      .idea
      , etc.).
    • Archivos temporales (como
      .DS_Store
      en macOS).
    • Archivos de control de versiones (como la carpeta
      .git
      ).
    • Cualquier otro archivo que no sea necesario para que el tema funcione.
  3. Comprueba los nombres de los archivos y carpetas:
    • Asegúrate de que no hay espacios ni caracteres especiales en los nombres de los archivos y carpetas. Usa guiones bajos o guiones para separar palabras.
    • Usa minúsculas para los nombres de los archivos y carpetas.
  4. Crea un archivo ZIP:
    • Selecciona todos los archivos y carpetas de tu tema (dentro de la carpeta de tu tema, *no* la carpeta del tema en sí).
    • Haz clic derecho y elige "Comprimir" (en Windows) o "Crear archivo" (en macOS). También puedes usar herramientas de compresión como 7-Zip o WinRAR.
    • Ponle al archivo ZIP el mismo nombre que la carpeta de tu tema (por ejemplo,
      mi-tema-personalizado.zip
      ).
¡Y eso es todo! Ya tienes tu tema empaquetado y listo para ser distribuido. Opciones de distribución:
  • Distribución manual: Puedes enviar el archivo ZIP directamente a otros usuarios, o subirlo a un servicio de almacenamiento en la nube (como Dropbox, Google Drive, etc.) y compartir el enlace.
  • Subirlo a tu propio sitio web: Puedes subir el archivo ZIP a tu propio sitio web y ofrecerlo para su descarga.
  • Subirlo al directorio de temas de WordPress.org: Si quieres que tu tema esté disponible para millones de usuarios de WordPress, puedes subirlo al directorio de temas de WordPress.org. Para ello, debes seguir las directrices del directorio de temas: https://developer.wordpress.org/themes/getting-started/theme-submission-requirements/. Tu tema será revisado por el equipo de revisión de temas de WordPress.org antes de ser aprobado.
Consideraciones Finales
  • Licencia: Si vas a distribuir publicamente tu tema, considera añadir un archivo
    license.txt
    que especifique los términos bajo los cuales se puede usar y distribuir tu tema. La mayoria de temas en wordpress usan la licencia GPL.
  • Documentación: Si vas a distribuir publicamente tu tema, considera añadir un archivo
    readme.txt
    o
    readme.md
    , con instrucciones para su uso.

Conclusión

¡Felicidades! Has llegado al final de este extenso recorrido sobre cómo crear un tema de WordPress desde cero. Hemos cubierto una gran cantidad de terreno, desde la configuración del entorno de desarrollo hasta el empaquetado y distribución de tu tema. Ahora tienes una base sólida de conocimientos para construir tus propios temas personalizados y dar rienda suelta a tu creatividad. Crear un tema de WordPress desde cero puede parecer una tarea abrumadora al principio, pero como has visto, se puede dividir en pasos más pequeños y manejables. No tengas miedo de experimentar, de probar cosas nuevas, y de cometer errores. Los errores son parte del proceso de aprendizaje, y te ayudarán a crecer como desarrollador. Recuerda que este post es solo el punto de partida. Hay mucho más que aprender sobre el desarrollo de temas de WordPress. A medida que vayas adquiriendo más experiencia, podrás explorar temas más avanzados, como:
  • Creación de custom post types y taxonomías personalizadas.
  • Desarrollo de plugins para extender la funcionalidad de tu tema.
  • Uso de frameworks CSS (como Bootstrap o Tailwind CSS).
  • Uso de preprocesadores CSS (como Sass o Less).
  • Integración con APIs externas.
  • Optimización del rendimiento de tu tema.
  • Desarrollo de temas para WooCommerce.
  • Y mucho más...
La comunidad de WordPress es enorme y muy activa. Hay una gran cantidad de recursos disponibles online (documentación, tutoriales, foros, blogs, etc.) que te pueden ayudar en tu camino. No dudes en buscar ayuda si la necesitas. ¡Y no te olvides de compartir tus conocimientos con otros! Espero que este post te haya sido útil. ¡Ahora, sal y construye algo increíble!