Desarrollo de Temas
2.5.x ✅ 4.0.x ✅
Esta guía explica cómo crear temas de XOOPS, incluyendo estructura de temas, herencia de plantillas y mejores prácticas para crear temas responsive y modernos.
Documentación relacionada
Sección titulada «Documentación relacionada»- Smarty-Basics - Fundamentos de Smarty en XOOPS
- Template-Variables - Variables disponibles en plantillas
- Smarty-4-Migration - Actualización de Smarty 3 a 4
Estructura del tema
Sección titulada «Estructura del tema»Un tema de XOOPS consta de la siguiente estructura de directorios:
themes/ mytheme/ theme.tpl # Main theme template theme_autorun.php # Auto-executed PHP (optional) XOOPS_version.php # Theme configuration css/ style.css # Main stylesheet custom.css # Custom styles images/ logo.png # Theme images js/ custom.js # Theme JavaScript language/ english/ main.php # Language stringsXOOPS_version.php
Sección titulada «XOOPS_version.php»El archivo de configuración del tema define las propiedades del tema:
<?php$themeversion = [ 'name' => 'My Theme', 'description' => 'A modern responsive XOOPS theme', 'version' => '1.0.0', 'author' => 'Your Name', 'author_url' => 'https://yoursite.com', 'license' => 'GPL-2.0', 'credits' => 'Based on Bootstrap 5', 'parent' => '', // Parent theme name for inheritance 'screenshots' => [ 'screenshot.png', ], 'features' => [ 'responsive' => true, 'rtl' => false, ],];Estructura básica de theme.tpl
Sección titulada «Estructura básica de theme.tpl»<!DOCTYPE html><html lang="<{$xoops_langcode}>"><head> <meta charset="<{$xoops_charset}>"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title><{$xoops_pagetitle}></title>
<{* Meta tags *}> <meta name="description" content="<{$xoops_meta_description}>"> <meta name="keywords" content="<{$xoops_meta_keywords}>"> <meta name="robots" content="<{$xoops_meta_robots}>"> <meta name="author" content="<{$xoops_meta_author}>"> <meta name="generator" content="XOOPS">
<{* CSS files *}> <link rel="stylesheet" href="<{$xoops_themecss}>"> <link rel="stylesheet" href="<{$xoops_url}>/themes/<{$xoops_theme}>/css/custom.css">
<{* Additional head content *}> <{$xoops_module_header}></head>
<body> <{* Header *}> <header> <div class="container"> <a href="<{$xoops_url}>"> <img src="<{$xoops_imageurl}>images/logo.png" alt="<{$xoops_sitename}>"> </a> <h1><{$xoops_sitename}></h1> </div> </header>
<{* Navigation *}> <nav> <{$xoops_mainmenu}> </nav>
<{* Content area *}> <main class="container"> <{* Left blocks *}> <{if $xoops_showlblock}> <aside class="left-blocks"> <{foreach item=block from=$xoops_lblocks}> <{include file="db:system_block_$block.template" block=$block}> <{/foreach}> </aside> <{/if}>
<{* Main content *}> <div class="content"> <{$xoops_contents}> </div>
<{* Right blocks *}> <{if $xoops_showrblock}> <aside class="right-blocks"> <{foreach item=block from=$xoops_rblocks}> <{include file="db:system_block_$block.template" block=$block}> <{/foreach}> </aside> <{/if}> </main>
<{* Footer *}> <footer> <div class="container"> <p>© <{$smarty.now|date_format:"%Y"}> <{$xoops_sitename}></p> <{$xoops_footer}> </div> </footer>
<{* JavaScript *}> <script src="<{$xoops_url}>/themes/<{$xoops_theme}>/js/custom.js"></script> <{$xoops_js}></body></html>Herencia de plantillas
Sección titulada «Herencia de plantillas»La herencia de plantillas de Smarty le permite crear temas secundarios que heredan de un tema padre.
Tema padre (base.tpl)
Sección titulada «Tema padre (base.tpl)»<!DOCTYPE html><html><head> <title>{block name=title}{/block} - <{$xoops_sitename}></title> {block name=head_css} <link rel="stylesheet" href="<{$xoops_themecss}>"> {/block}</head><body> {block name=header} <header> <h1><{$xoops_sitename}></h1> </header> {/block}
{block name=content} <main> <{$xoops_contents}> </main> {/block}
{block name=footer} <footer> <p>© <{$smarty.now|date_format:"%Y"}></p> </footer> {/block}</body></html>Tema secundario (theme.tpl)
Sección titulada «Tema secundario (theme.tpl)»{extends file="db:parenttheme/theme.tpl"}
{block name=title}My Custom Title{/block}
{block name=head_css} {$smarty.block.parent} {* Include parent CSS *} <link rel="stylesheet" href="<{$xoops_url}>/themes/childtheme/css/custom.css">{/block}
{block name=header} <header class="custom-header"> <div class="logo"> <img src="<{$xoops_imageurl}>images/logo.png" alt="Logo"> </div> <nav class="main-nav"> <{$xoops_mainmenu}> </nav> </header>{/block}Creación de variaciones de temas
Sección titulada «Creación de variaciones de temas»Cree múltiples variaciones de tema desde un tema base:
xbootstrap-green/theme.tpl:
{extends file="db:xbootstrap/theme.tpl"}
{block name=css}<link rel="stylesheet" href="<{$xoops_url}>/themes/xbootstrap-green/css/green.css">{/block}xbootstrap-green/XOOPS_version.php:
<?php$themeversion = [ 'name' => 'xbootstrap-green', 'parent' => 'xbootstrap', // ... other settings];theme_autorun.php
Sección titulada «theme_autorun.php»Este archivo se ejecuta automáticamente y se puede usar para preparar datos para plantillas:
<?php/** @var XoopsTpl $xoopsTpl */global $xoopsTpl;
if (!empty($xoopsTpl)) { // Add configuration directory $xoopsTpl->addConfigDir(__DIR__);}
// Include module autoloader if neededif (file_exists(XOOPS_ROOT_PATH . '/modules/publisher/preloads/autoloader.php')) { require XOOPS_ROOT_PATH . '/modules/publisher/preloads/autoloader.php';}
use XoopsModules\Publisher\Helper;use XoopsModules\Publisher\Constants;
/** * Obtener elementos para mostrar en el tema */function getPublisherItems($limit, $sort = 'RAND()', $order = ''){ $helper = Helper::getInstance(); $itemsObj = $helper->getHandler('Item')->getItems( $limit, 0, // start [Constants::PUBLISHER_STATUS_PUBLISHED], -1, // categoryid $sort, $order );
$items = []; if ($itemsObj) { foreach ($itemsObj as $itemObj) { $newItem = [ 'itemid' => $itemObj->itemid(), 'title' => $itemObj->title(), 'body' => $itemObj->body(), 'votes' => $itemObj->votes(), 'counter' => $itemObj->counter(), 'image' => XOOPS_URL . '/uploads/blank.gif', ];
$images = $itemObj->getImages(); if (isset($images['main']) && is_object($images['main'])) { $newItem['image'] = XOOPS_URL . '/uploads/' . $images['main']->getVar('image_name'); }
$items[] = $newItem; } } return $items;}
// Asignar datos a plantillas$xoopsTpl->assign('sliderItems', getPublisherItems(9));$xoopsTpl->assign('featuredItems', getPublisherItems(3));$xoopsTpl->assign('latestItems', getPublisherItems(4));$xoopsTpl->assign('xoops_url', XOOPS_URL);Usando Bootstrap
Sección titulada «Usando Bootstrap»Ejemplo de tema Bootstrap 5:
<!DOCTYPE html><html lang="<{$xoops_langcode}>"><head> <meta charset="<{$xoops_charset}>"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title><{$xoops_pagetitle}></title>
{* Bootstrap CSS *} <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> <link rel="stylesheet" href="<{$xoops_url}>/themes/<{$xoops_theme}>/css/custom.css">
<{$xoops_module_header}></head><body> {* Navigation *} <nav class="navbar navbar-expand-lg navbar-light bg-light"> <div class="container"> <a class="navbar-brand" href="<{$xoops_url}>"> <{$xoops_sitename}> </a> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarNav"> <{$xoops_mainmenu}> </div> </div> </nav>
{* Main content *} <div class="container my-4"> <div class="row"> {* Left sidebar *} <{if $xoops_showlblock}> <div class="col-lg-3"> <{foreach item=block from=$xoops_lblocks}> <div class="card mb-3"> <div class="card-header"><{$block.title}></div> <div class="card-body"><{$block.content}></div> </div> <{/foreach}> </div> <{/if}>
{* Main content area *} <div class="col-lg-<{if $xoops_showlblock && $xoops_showrblock}>6<{elseif $xoops_showlblock || $xoops_showrblock}>9<{else}>12<{/if}>"> <{$xoops_contents}> </div>
{* Right sidebar *} <{if $xoops_showrblock}> <div class="col-lg-3"> <{foreach item=block from=$xoops_rblocks}> <div class="card mb-3"> <div class="card-header"><{$block.title}></div> <div class="card-body"><{$block.content}></div> </div> <{/foreach}> </div> <{/if}> </div> </div>
{* Footer *} <footer class="bg-dark text-white py-4 mt-auto"> <div class="container text-center"> <p class="mb-0">© <{$smarty.now|date_format:"%Y"}> <{$xoops_sitename}></p> <{$xoops_footer}> </div> </footer>
{* Bootstrap JS *} <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script> <{$xoops_js}></body></html>Plantillas de bloques
Sección titulada «Plantillas de bloques»Cree plantillas de bloques personalizados:
{* themes/mytheme/templates/system_block.tpl *}<div class="block"> <{if $block.title}> <h3 class="block-title"><{$block.title}></h3> <{/if}> <div class="block-content"> <{$block.content}> </div></div>Carrusel/Deslizador personalizado
Sección titulada «Carrusel/Deslizador personalizado»Ejemplo de un carrusel de contenido dinámico:
{* Slider using theme_autorun.php data *}<{if $sliderItems}><div class="owl-carousel owl-theme"> <{foreach item=item from=$sliderItems}> <div class="owl-carousel-info-wrap item"> <img src="<{$item.image}>" class="owl-carousel-image img-fluid" alt="<{$item.title}>">
<div class="owl-carousel-info"> <h4 class="mb-2"> <a href="<{$xoops_url}>/modules/publisher/item.php?itemid=<{$item.itemid}>"> <{$item.title|truncate:15}> </a> </h4> <span class="badge">Reads: <{$item.counter}></span> <span class="badge">Votes: <{$item.votes}></span> </div> </div> <{/foreach}></div><{/if}>Consejos de diseño responsivo
Sección titulada «Consejos de diseño responsivo»CSS Primero Móvil
Sección titulada «CSS Primero Móvil»/* Estilos base para móvil */.content { width: 100%; padding: 1rem;}
/* Tablet y superior */@media (min-width: 768px) { .content { width: 75%; padding: 2rem; }}
/* Escritorio y superior */@media (min-width: 1024px) { .content { width: 60%; padding: 3rem; }}Visualización condicional de bloques
Sección titulada «Visualización condicional de bloques»{* Ocultar bloques en móvil usando clases CSS *}<{if $xoops_showlblock}><aside class="left-blocks d-none d-lg-block"> <{foreach item=block from=$xoops_lblocks}> <{include file="db:system_block.tpl" block=$block}> <{/foreach}></aside><{/if}>Mejores prácticas
Sección titulada «Mejores prácticas»Usar HTML semántico
Sección titulada «Usar HTML semántico»<header>...</header><nav>...</nav><main>...</main><aside>...</aside><footer>...</footer>Optimizar activos
Sección titulada «Optimizar activos»{* Diferir JavaScript no crítico *}<script src="script.js" defer></script>
{* Async para scripts independientes *}<script src="analytics.js" async></script>Accesibilidad
Sección titulada «Accesibilidad»{* Usar etiquetas ARIA apropiadas *}<nav aria-label="Navegación principal"> <{$xoops_mainmenu}></nav>
{* Proporcionar texto alternativo para imágenes *}<img src="<{$item.image}>" alt="<{$item.title|escape}>">
{* Enlaces de salto para navegación por teclado *}<a href="#main-content" class="skip-link">Saltar al contenido</a>Rendimiento
Sección titulada «Rendimiento»{* Cargar imágenes de forma perezosa *}<img src="<{$item.image}>" loading="lazy" alt="<{$item.title}>">
{* Precargar recursos críticos *}<link rel="preload" href="fonts/custom.woff2" as="font" type="font/woff2" crossorigin>#themes #smarty #xoops #css #design #responsive