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.
- 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.
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.
- 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/
Instalación de WordPress
Una vez que tienes tu servidor local funcionando, necesitas instalar WordPress. Hay dos formas principales de hacerlo:- Instalación manual:
- Descarga la última versión de WordPress desde wordpress.org.
- 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).
- 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.
- Renombra el archivo a
wp-config-sample.php
.wp-config.php
- Abre el archivo y edita las siguientes líneas con los datos de tu base de datos:
wp-config.php
- : El nombre de la base de datos que creaste.
DB_NAME
- : El nombre de usuario de la base de datos (por defecto, suele ser "root").
DB_USER
- : La contraseña de la base de datos (si la has configurado).
DB_PASSWORD
- : El host de la base de datos (normalmente, "localhost").
DB_HOST
- Abre tu navegador y escribe la dirección de tu sitio local (por ejemplo, ). Sigue las instrucciones de instalación de WordPress.
http://localhost/misitio
- 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.
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/
wp-content/themes
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.
wp-content/themes
mi_tema_personalizado
style.css
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.
La Hoja de Estilos (style.css) - Cabecera del Tema
Abre el archivostyle.css
/*
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;
}
- 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).
El Archivo Principal (index.php)
Abre el archivoindex.php
<?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() && ! 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();
?>
- 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 de tu tema (si existe). El
header.php
suele contener el encabezado de tu sitio (etiquetaheader.php
, menú de navegación, etc.). Lo crearemos en la siguiente sección.<head>
: 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 (o
content.php
, si existe) que se encuentra dentro de la carpetacontent-{post-type}.php
. Este archivo se encargará de mostrar el contenido de cada entrada. Lo crearemos más adelante.template-parts
- 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 (que también crearemos más adelante).
content-none.php
- get_sidebar(): Esta función incluye el archivo de tu tema (si existe). El
sidebar.php
suele contener la barra lateral de tu sitio.sidebar.php
- get_footer(): Esta función incluye el archivo de tu tema (si existe). El
footer.php
suele contener el pie de página de tu sitio (copyright, enlaces, etc.).footer.php
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 archivoheader.php
- La etiqueta de apertura .
<!DOCTYPE html>
- La etiqueta con el atributo de idioma.
<html>
- La etiqueta con:
<head>
- 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
- La etiqueta de apertura con la función
<body>
.body_class()
- El menú de navegación principal.
- Un contenedor para el contenido principal (por ejemplo, un con la clase "site-content").
<div>
header.php
<!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() && 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">
- : Imprime los atributos de idioma de la etiqueta
language_attributes()
.<html>
- : Obtiene el juego de caracteres de tu sitio WordPress.
bloginfo( 'charset' )
- : Muestra el título de la página actual, con un separador (|) y el nombre del sitio a la derecha.
wp_title( '|', true, 'right' )
- : Esta función es *muy* importante. Inserta código esencial en la etiqueta
wp_head()
, como enlaces a hojas de estilo, scripts, metadatos, etc. Muchos plugins dependen de esta función para funcionar correctamente. *Nunca* la olvides.<head>
- : Esta función añade clases CSS a la etiqueta
body_class()
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.<body>
- : 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).
is_front_page() && is_home()
- : Devuelve la URL de la página de inicio de tu sitio.
home_url( '/' )
- : Obtiene el nombre de tu sitio WordPress.
bloginfo( 'name' )
- : Obtiene la descripción corta(tagline) de tu sitio.
get_bloginfo( 'description', 'display' )
- : 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
wp_nav_menu()
más adelante).functions.php
footer.php (El Pie de Página)
El archivofooter.php
- Información de copyright.
- Enlaces a redes sociales (opcional).
- La función .
wp_footer()
- La etiqueta de cierre .
</body>
- La etiqueta de cierre .
</html>
footer.php
</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>
- Cerramos el div que abrimos en el header.
#content
- : Esta función se usa para la traducción de cadenas de texto. Permite que tu tema sea traducido a otros idiomas.
__()
- : Esta función "escapa" una URL, asegurándose de que sea segura. Es una buena práctica usarla siempre que muestres una URL.
esc_url()
- y
printf()
: Se usan para mostrar texto traducible que puede contener variables.esc_html__()
- : Esta función, al igual que
wp_footer()
, es *muy* importante. Inserta código esencial en la parte inferior de tu página, justo antes de la etiqueta de cierrewp_head()
. Muchos plugins dependen de esta función. *Nunca* la olvides.</body>
sidebar.php (La Barra Lateral - Opcional)
El archivosidebar.php
sidebar.php
<?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 -->
- : Comprueba si la barra lateral con el ID 'sidebar-1' tiene algún widget activo. Si no tiene widgets, no se muestra nada.
is_active_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.
dynamic_sidebar( 'sidebar-1' )
functions.php (Funcionalidades del Tema)
El archivofunctions.php
- 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...
functions.php
<?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() && comments_open() && get_option( 'thread_comments' ) ) {
wp_enqueue_script( 'comment-reply' );
}
}
add_action( 'wp_enqueue_scripts', 'mi_tema_personalizado_scripts' );
- : 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.
_S_VERSION
- : Esta función se ejecuta después de que el tema se haya cargado (hook
mi_tema_personalizado_setup()
). Aquí es donde configuramos las características básicas del tema.after_setup_theme
- : Carga los archivos de traducción del tema.
load_theme_textdomain()
- : Añade soporte para diversas características de WordPress, como:
add_theme_support()
- : Añade enlaces a los feeds RSS en la etiqueta
automatic-feed-links
.<head>
- : Permite que WordPress gestione la etiqueta
title-tag
.<title>
- : Habilita las imágenes destacadas para entradas y páginas.
post-thumbnails
- : Permite usar etiquetas HTML5 en formularios de búsqueda, comentarios, etc.
html5
- : Permite personalizar el fondo del sitio.
custom-background
- : Permite la actualización selectiva de widgets en el Personalizador.
customize-selective-refresh-widgets
- : Permite añadir un logo personalizado a través del Personalizador.
custom-logo
- : Registra un menú de navegación llamado "menu-principal". Este es el menú que mostramos en
register_nav_menus()
.header.php
- : Establece el ancho máximo del contenido.
mi_tema_personalizado_content_width()
- : Registra una barra lateral llamada "sidebar-1". Esta es la barra lateral que mostramos en
mi_tema_personalizado_widgets_init()
.sidebar.php
- : "Encola" (carga) las hojas de estilo y los scripts del tema.
mi_tema_personalizado_scripts()
- : Carga la hoja de estilos principal (
wp_enqueue_style()
).style.css
- : Añade soporte para estilos RTL (de derecha a izquierda).
wp_style_add_data()
- : Carga un archivo JavaScript llamado
wp_enqueue_script()
(lo crearemos más adelante). También carga el scriptnavigation.js
si estamos en una entrada individual, los comentarios están abiertos y los comentarios anidados están habilitados.comment-reply
/languages
navigation.js
/js
Creación de single.php (plantilla para entradas individuales)
El archivosingle.php
single.php
<?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();
single.php
index.php
- Incluimos, como en , el
index.php
, que mostrará el contenido.template-parts/content
- : Esta función muestra enlaces a la entrada anterior y siguiente. Hemos personalizado el texto de los enlaces.
the_post_navigation()
- : Comprueba si los comentarios están abiertos o si hay algún comentario.
comments_open() || get_comments_number()
- : Si los comentarios están abiertos o hay comentarios, se carga la plantilla de comentarios (
comments_template()
). La crearemos más adelante.comments.php
Creando page.php (plantilla para paginas)
Mientras quesingle.php
page.php
single.php
index.php
<?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 . Esto significa que crearemos un archivo llamado
get_template_part( 'template-parts/content', 'page' )
dentro de la carpetacontent-page.php
para mostrar el contenido de las páginas.template-parts
- 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
<?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();
Template Name: Mi Plantilla Personalizada
Template Post Type: page
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 buclewhile
<?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;
?>
- : Esta es la condición inicial. La función
if ( 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 delhave_posts()
.if
- : Este es el bucle en sí. La función
while ( have_posts() ) : the_post();
se vuelve a evaluar en cada iteración. Mientras siga habiendo entradas, el bucle continúa. La funciónhave_posts()
es *crucial*. Prepara la entrada actual para que puedas acceder a sus datos con funciones comothe_post()
,the_title()
, etc. Sinthe_content()
, estas funciones no funcionarían correctamente.the_post()
- : Dentro del bucle, puedes usar las funciones de WordPress para mostrar el contenido de la entrada actual.
// Aquí va el código para mostrar el contenido de cada entrada.
- : Cierra el bucle
endwhile;
.while
- : Esta parte es opcional. Aquí puedes poner el código que se ejecutará si no hay entradas que coincidan con la consulta.
else :
- : Cierra la condición
endif;
.if
Implementación del Loop en index.php, single.php, page.php, etc.
Ya hemos visto el Loop en acción en los archivosindex.php
single.php
page.php
index.php
single.php
index.php
<?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;
?>
- : Obtiene el ID de la entrada actual.
the_ID()
- : Añade clases CSS a la etiqueta
post_class()
que describen la entrada.<article>
- : Muestra el título de la entrada. Lo hemos envuelto en un enlace (
the_title()
) que apunta a la URL de la entrada individual (<a>
).get_permalink()
- : Obtiene la URL permanente de la entrada actual.
get_permalink()
- : Obtiene el tipo de entrada (post, page, etc.).
get_post_type()
- : Muestra un resumen de la entrada.
the_excerpt()
- ,
mi_tema_personalizado_posted_on()
ymi_tema_personalizado_posted_by()
: Estas son *funciones personalizadas* que crearemos enmi_tema_personalizado_entry_footer()
para mostrar la fecha, el autor y los metadatos del footer de la entrada, respectivamente.functions.php
- : Función personalizada para mostrar la imagen destacada.
mi_tema_personalizado_post_thumbnail()
functions.php
functions.php
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() && ! post_password_required() && ( 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;
- : Mostrar la fecha de publicación de la entrada.
mi_tema_personalizado_posted_on()
- : Mostrar el autor de la entrada.
mi_tema_personalizado_posted_by()
- : Mostrar las categorías, etiquetas y enlace a comentarios.
mi_tema_personalizado_entry_footer()
- : Muestra la imagen destacada, si la hay. Si estamos en una vista de archivo (como
mi_tema_personalizado_post_thumbnail()
), la imagen se envuelve en un enlace a la entrada individual.index.php
template-parts
content.php
content-page.php
content-none.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(); ?> -->
<?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(); ?> -->
<?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() && 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:- : Muestra el título de la entrada.
the_title()
- : Muestra el contenido completo de la entrada.
the_content()
- : Muestra un resumen de la entrada.
the_excerpt()
- : Muestra la URL permanente de la entrada.
the_permalink()
- : Muestra el ID de la entrada.
the_ID()
- : Muestra el nombre del autor de la entrada.
the_author()
- : Muestra la fecha de publicación de la entrada.
the_date()
- : Muestra la hora de publicación de la entrada.
the_time()
- : Muestra las categorías a las que pertenece la entrada.
the_category()
- : Muestra las etiquetas de la entrada.
the_tags()
- : Muestra la imagen destacada de la entrada.
the_post_thumbnail()
- : Devuelve la URL de la entrada, en lugar de mostrarla directamente. Es útil para usarla dentro de atributos
get_permalink()
, por ejemplo.href
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>
<script>
header.php
footer.php
wp_enqueue_style()
wp_enqueue_script()
wp_enqueue_scripts
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() && comments_open() && get_option( 'thread_comments' ) ) {
wp_enqueue_script( 'comment-reply' );
}
}
add_action( 'wp_enqueue_scripts', 'mi_tema_personalizado_scripts' );
- :
wp_enqueue_style( $handle, $src, $deps, $ver, $media )
- : Un identificador único para tu hoja de estilos (por ejemplo, 'mi-tema-personalizado-style').
$handle
- : La URL de tu hoja de estilos.
$src
devuelve la URL de la hoja de estilos principal de tu tema (get_stylesheet_uri()
).style.css
- : 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.
$deps
- : 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
$ver
en_S_VERSION
para esto.functions.php
- : El tipo de medio para el que se aplica esta hoja de estilos (por ejemplo, 'all', 'screen', 'print'). Por defecto es 'all'.
$media
- : 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_style_add_data( 'mi-tema-personalizado-style', 'rtl', 'replace' )
- :
wp_enqueue_script( $handle, $src, $deps, $ver, $in_footer )
- : Un identificador único para tu script.
$handle
- : La URL de tu script.
$src
devuelve la URL del directorio de tu tema.get_template_directory_uri()
- : Un array de dependencias. Si tu script depende de otro script (por ejemplo, jQuery), puedes especificar su identificador aquí.
$deps
- : El número de versión de tu script.
$ver
- : Un valor booleano que indica si el script debe cargarse en el pie de página (
$in_footer
) o en el encabezado (true
). Por defecto esfalse
. 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.false
- : Esta línea carga el script
if ( is_singular() && comments_open() && get_option( 'thread_comments' ) ) { wp_enqueue_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 (comment-reply
), los comentarios están abiertos (is_singular()
) y los comentarios anidados están habilitados (comments_open()
).get_option( 'thread_comments' )
- : Engancha nuestra función
add_action( 'wp_enqueue_scripts', 'mi_tema_personalizado_scripts' );
al hookmi_tema_personalizado_scripts
. Esto le dice a WordPress que ejecute nuestra función cuando sea el momento de cargar los estilos y scripts.wp_enqueue_scripts
/js/navigation.js
( 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 ) );
} )();
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 gigante, puedes dividir tu CSS en archivos más pequeños y específicos (por ejemplo,
style.css
,header.css
,footer.css
,sidebar.css
, etc.). Luego, puedes importar estos archivos en tuforms.css
principal usando la directivastyle.css
(aunque esto puede afectar al rendimiento, es mejor encolarlos individualmente desde@import
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.functions.php
- 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.
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 (comothe_title()
the_content()
wp_enqueue_scripts()
Funciones de Encabezado (wp_head())
La funciónwp_head()
<head>
header.php
- Enlaces a hojas de estilo (tanto del tema como de plugins).
- Scripts (tanto del tema como de plugins).
- Metadatos (como la etiqueta , la descripción, etc.).
<title>
- Etiquetas para feeds RSS.
<link>
- Y mucho más...
wp_head()
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>
<?php wp_head(); ?>
</head>
Funciones de Pie de Página (wp_footer())
La funciónwp_footer()
wp_head()
</body>
footer.php
- 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...
wp_head()
wp_footer()
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:- : Incluye el archivo
get_header()
.header.php
- : Incluye el archivo
get_footer()
.footer.php
- : Incluye el archivo
get_sidebar()
.sidebar.php
get_template_part()
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:- : Verifica si la página actual es la página de inicio (que muestra las últimas entradas).
is_home()
- : 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_front_page()
- : Verifica si la página actual es una entrada individual.
is_single()
- : Verifica si la página actual es una página estática.
is_page()
- : Verifica si la página actual utiliza una plantilla de página específica.
is_page_template()
- : Verifica si estamos mostrando un único elemento, ya sea post, página o custom post type.
is_singular()
- : 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_archive()
- : Verifica si la página actual es una página de categoría.
is_category()
- : Verifica si la página actual es una página de etiqueta.
is_tag()
- : Verifica si la página actual es una página de autor.
is_author()
- : Verifica si la página actual es una página de resultados de búsqueda.
is_search()
- : Verifica si la página actual es una página de error 404 (página no encontrada).
is_404()
- : Verifica si los comentarios están abiertos para la entrada actual.
comments_open()
- : Verifica si los pings (trackbacks y pingbacks) están abiertos para la entrada actual.
pings_open()
- : Verifica si el post tiene una imagen destacada.
has_post_thumbnail()
- : Verifica si el usuario actual ha iniciado sesión.
is_user_logged_in()
- : Verifica si el usuario actual tiene un permiso determinado.
current_user_can( $capability )
if
elseif
else
<?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>';
}
?>
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ónregister_sidebar()
widgets_init
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' );
register_sidebar()
- : El nombre del área de widgets (que se mostrará en el panel de administración).
name
- : Un identificador único para el área de widgets. Debe ser en minúsculas y sin espacios (usa guiones bajos o guiones).
id
- : Una descripción del área de widgets (que se mostrará en el panel de administración).
description
- : El código HTML que se insertará *antes* de cada widget.
before_widget
se reemplaza por el ID del widget, y%1$s
se reemplaza por las clases CSS del widget.%2$s
- : El código HTML que se insertará *después* de cada widget.
after_widget
- : El código HTML que se insertará *antes* del título de cada widget.
before_title
- : El código HTML que se insertará *después* del título de cada widget.
after_title
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óndynamic_sidebar()
sidebar.php
<?php
if ( ! is_active_sidebar( 'sidebar-1' ) ) {
return;
}
?>
<aside id="secondary" class="widget-area">
<?php dynamic_sidebar( 'sidebar-1' ); ?>
</aside><!-- #secondary -->
- : Comprueba si hay algún widget activo en ese area.
is_active_sidebar( 'sidebar-1' )
- : Muestra los widgets.
dynamic_sidebar( 'sidebar-1' )
dynamic_sidebar()
footer.php
</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>
if ( is_active_sidebar( 'footer-1' ) )
dynamic_sidebar( 'footer-1' )
register_sidebar()
dynamic_sidebar()
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()
add_control()
customize_register
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' );
- : Esta es la función que se ejecutará cuando se cargue el Personalizador. Recibe un objeto
mi_tema_personalizado_customize_register( $wp_customize )
como parámetro, que es el que usaremos para añadir nuestras opciones.$wp_customize
- : Añade una *sección* al Personalizador. Las secciones agrupan controles relacionados.
$wp_customize->add_section( 'mi_tema_personalizado_colors', array(...) )
- : El ID único de la sección.
'mi_tema_personalizado_colors'
- : El título de la sección (que se mostrará en el Personalizador).
'title'
- : La prioridad de la sección (un número que determina su orden).
'priority'
- : Añade una *configuración* (setting). Una configuración representa un valor que se puede personalizar.
$wp_customize->add_setting( 'header_background_color', array(...) )
- : El ID único de la configuración.
'header_background_color'
- : El valor por defecto de la configuración.
'default'
- : 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_callback'
, que se asegura de que el valor sea un código de color hexadecimal válido.sanitize_hex_color
- : Determina cómo se actualiza la vista previa cuando se cambia el valor de la configuración.
'transport'
recarga la página, mientras que'refresh'
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).'postMessage'
- : 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.).
$wp_customize->add_control( new WP_Customize_Color_Control( $wp_customize, 'header_background_color', array(...) ) )
- : Crea un nuevo control de tipo "selector de color". WordPress tiene muchos tipos de controles predefinidos (
new WP_Customize_Color_Control()
,WP_Customize_Control
,WP_Customize_Image_Control
, etc.).WP_Customize_Upload_Control
- : El objeto del Personalizador.
$wp_customize
- : El ID del control.
'header_background_color'
- : La etiqueta del control (que se mostrará en el Personalizador).
'label'
- : El ID de la sección a la que pertenece este control.
'section'
- : El ID de la configuración a la que está vinculado este control.
'settings'
- : Engancha nuestra función al hook
add_action( 'customize_register', 'mi_tema_personalizado_customize_register' )
.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ónget_theme_mod()
header.php
<header>
<header id="masthead" class="site-header" style="background-color: <?php echo get_theme_mod( 'header_background_color', '#ffffff' ); ?>;">
- : Obtiene el valor de la configuración
get_theme_mod( 'header_background_color', '#ffffff' )
. El segundo parámetro ('header_background_color'
) 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).'#ffffff'
- 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...
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:- 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
El dominio de texto debe coincidir con el nombre de la carpeta de tu tema (sin espacios ni caracteres especiales)./* Text Domain: mi-tema-personalizado */
- Carga el dominio de texto: Debes cargar el dominio de texto en tu archivo . Ya lo hicimos en la función
functions.php
:mi_tema_personalizado_setup()
Esto le dice a WordPress que busque los archivos de traducción en la carpetaload_theme_textdomain( 'mi-tema-personalizado', get_template_directory() . '/languages' );
dentro de tu tema./languages
- 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' ); ?>
- : Muestra la traducción de una cadena de texto (similar a
_e()
).echo __()
<?php _e( 'Hola Mundo', 'mi-tema-personalizado' ); ?>
- : Devuelve la traducción de una cadena de texto, y la "escapa" para que sea segura para mostrar en HTML.
esc_html__()
<?php echo esc_html__( 'Hola Mundo', 'mi-tema-personalizado' ); ?>
- : Muestra la traducción de una cadena de texto, y la "escapa" para que sea segura.
esc_html_e()
<?php esc_html_e( 'Hola Mundo', 'mi-tema-personalizado' ); ?>
- : Devuelve la traducción de una cadena, y la "escapa" para usarla en atributos HTML.
esc_attr__()
<a title="<?php esc_attr_e( 'Enlace de ejemplo', 'mi-tema-personalizado' ); ?>">...</a>
- : Muestra la traducción de una cadena, y la "escapa" para atributos.
esc_attr_e()
- y
printf()
: Se usan para mostrar cadenas de texto que contienen variables. Debes usar funciones de traducción dentro desprintf()
oprintf()
.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>
<h1><?php esc_html_e( 'Título de la página', 'mi-tema-personalizado' ); ?></h1>
<a href="#" title="<?php esc_attr_e( 'Enlace de ejemplo', 'mi-tema-personalizado' ); ?>"><?php esc_html_e( 'Haz clic aquí', 'mi-tema-personalizado' ); ?></a>
<?php
$nombre = 'Juan';
printf(
/* translators: %s is the user's name. */
__( 'Hola, %s', 'mi-tema-personalizado' ),
$nombre
);
?>
- : Esto permite añadir contexto para los traductores.
/* translators: */
.po
.mo
- 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 . Ejecuta este comando desde la carpeta de tu tema:
wp i18n make-pot
Esto generará un archivo llamadowp i18n make-pot . languages/mi-tema-personalizado.pot
en la carpetami-tema-personalizado.pot
./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.
- WP-CLI: Si tienes WP-CLI instalado, puedes usar el comando
- 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 . Puedes usar Poedit o Loco Translate para crear y editar archivos PO.
es_ES.po
- Traduce las cadenas de texto: Abre el archivo PO con Poedit o Loco Translate, y traduce cada cadena de texto.
- 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
- Coloca los archivos .po y .mo en la carpeta languages.
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/
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()
, etc.sanitize_text_field()
- 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)
wp-config.php
WP_DEBUG
true
define( 'WP_DEBUG', true );
WP_DEBUG
WP_DEBUG_LOG
WP_DEBUG_DISPLAY
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );
- : Guarda todos los errores en un archivo llamado
WP_DEBUG_LOG
dentro de la carpetadebug.log
.wp-content
- : Controla si los errores se muestran o no en el HTML de las páginas. En este caso, lo hemos establecido en
WP_DEBUG_DISPLAY
para que los errores no se muestren en el sitio, pero sí se guarden en el archivo de registro.false
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:- Asegúrate de que tienes todos los archivos esenciales:
- (con la cabecera del tema).
style.css
- .
index.php
- .
header.php
- .
footer.php
- .
functions.php
- (una imagen de captura de pantalla de tu tema, de 1200x900 píxeles).
screenshot.png
- Cualquier otro archivo de plantilla que hayas creado (,
single.php
,page.php
,sidebar.php
, etc.).archive.php
- Carpetas ,
/js
,/css
,/images
,/languages
,/template-parts
(si las tienes)./inc
- Elimina archivos innecesarios:
- Archivos de configuración de tu editor de código (como ,
.vscode
, etc.)..idea
- Archivos temporales (como en macOS).
.DS_Store
- Archivos de control de versiones (como la carpeta ).
.git
- Cualquier otro archivo que no sea necesario para que el tema funcione.
- Archivos de configuración de tu editor de código (como
- 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.
- 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
- 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.
- Licencia: Si vas a distribuir publicamente tu tema, considera añadir un archivo 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.
license.txt
- Documentación: Si vas a distribuir publicamente tu tema, considera añadir un archivo o
readme.txt
, con instrucciones para su uso.readme.md
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...
Recientes
-
Sincronizar Google Calendar y Google Contacts con CRM Vtiger 6.xnoviembre 30th, 2016
-
Desactivar otros métodos de envío en magento 1.9 cuando el envíos es gratisnoviembre 24th, 2015
-
Como crear un template de WordPress desde 0febrero 19th, 2025
-
Despliegues automáticos usando GitLab CI/CDfebrero 19th, 2025
-
Políticas de seguridad automatizadas con OpenSCAPfebrero 18th, 2025