Implementar navbar sticky con Bootstrap 5 y animaciones - Issue #7
Implementación completa de navbar sticky con menú hamburguesa responsive según especificaciones del template del cliente: **Archivos Modificados:** - header.php: Reescritura completa con navbar Bootstrap 5, sticky positioning, y responsive hamburger menu - functions.php: Agregado require para nav-walker.php - inc/enqueue-scripts.php: Agregado enqueue de custom-style.css y main.js **Archivos Creados:** - assets/css/custom-style.css: Estilos navbar con animaciones (gradient underline, dropdown slideDown, etc.) - assets/js/main.js: JavaScript para scroll effect, active menu highlight, y mobile auto-close - inc/nav-walker.php: Bootstrap 5 Nav Walker para dropdowns WordPress **Características:** ✅ Navbar sticky con transición de sombra al hacer scroll ✅ Gradient underline animation en hover de nav-links ✅ Dropdown menus con animación slideDown ✅ Menú hamburguesa responsive (< 991px) ✅ Auto-close mobile menu al hacer click en enlaces ✅ Active menu item highlighting ✅ Smooth scroll para anchor links ✅ Skip link para accesibilidad ✅ Compatible con WordPress menu system 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
276
wp-content/themes/apus-theme/assets/css/custom-style.css
Normal file
276
wp-content/themes/apus-theme/assets/css/custom-style.css
Normal file
@@ -0,0 +1,276 @@
|
|||||||
|
/**
|
||||||
|
* Custom Styles - APUS Theme
|
||||||
|
*
|
||||||
|
* Estilos personalizados según el template del cliente.
|
||||||
|
* Incluye: Navbar sticky, animaciones, y componentes específicos.
|
||||||
|
*
|
||||||
|
* @package Apus_Theme
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ============================================
|
||||||
|
NAVBAR STICKY CON ANIMACIONES
|
||||||
|
============================================ */
|
||||||
|
|
||||||
|
.navbar {
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
z-index: 1030;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
box-shadow: 0 2px 4px rgba(0,0,0,0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar.scrolled {
|
||||||
|
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
|
||||||
|
background-color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Gradient underline animation en hover */
|
||||||
|
.nav-link {
|
||||||
|
position: relative;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
padding: 0.5rem 1rem !important;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-link::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%) scaleX(0);
|
||||||
|
width: 80%;
|
||||||
|
height: 2px;
|
||||||
|
background: linear-gradient(90deg, #0d6efd, #0dcaf0);
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-link:hover {
|
||||||
|
color: #0d6efd !important;
|
||||||
|
background-color: rgba(13, 110, 253, 0.05);
|
||||||
|
border-radius: 4px;
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-link:hover::after {
|
||||||
|
transform: translateX(-50%) scaleX(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Active nav link */
|
||||||
|
.nav-link.active,
|
||||||
|
.nav-item.current-menu-item > .nav-link {
|
||||||
|
color: #0d6efd !important;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-link.active::after,
|
||||||
|
.nav-item.current-menu-item > .nav-link::after {
|
||||||
|
transform: translateX(-50%) scaleX(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dropdown animations */
|
||||||
|
.dropdown-menu {
|
||||||
|
border: none;
|
||||||
|
box-shadow: 0 8px 24px rgba(0,0,0,0.12);
|
||||||
|
border-radius: 8px;
|
||||||
|
animation: slideDown 0.3s ease;
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slideDown {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-10px);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-item {
|
||||||
|
padding: 0.75rem 1.5rem;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-item:hover,
|
||||||
|
.dropdown-item:focus {
|
||||||
|
background: linear-gradient(90deg, rgba(13, 110, 253, 0.1), rgba(13, 202, 240, 0.1));
|
||||||
|
color: #0d6efd;
|
||||||
|
transform: translateX(5px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-item.active {
|
||||||
|
background-color: rgba(13, 110, 253, 0.1);
|
||||||
|
color: #0d6efd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Navbar Brand */
|
||||||
|
.navbar-brand {
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
color: #1a1a1a;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-brand:hover {
|
||||||
|
color: #0d6efd;
|
||||||
|
transform: scale(1.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Navbar Toggler (Hamburger) */
|
||||||
|
.navbar-toggler {
|
||||||
|
border: 2px solid rgba(0, 0, 0, 0.1);
|
||||||
|
padding: 0.5rem 0.75rem;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-toggler:hover {
|
||||||
|
border-color: #0d6efd;
|
||||||
|
background-color: rgba(13, 110, 253, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-toggler:focus {
|
||||||
|
box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mobile Menu Styles */
|
||||||
|
@media (max-width: 991px) {
|
||||||
|
.navbar-collapse {
|
||||||
|
margin-top: 1rem;
|
||||||
|
padding: 1rem 0;
|
||||||
|
border-top: 1px solid rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-link {
|
||||||
|
padding: 0.75rem 1rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-link::after {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-menu {
|
||||||
|
border: none;
|
||||||
|
box-shadow: none;
|
||||||
|
animation: none;
|
||||||
|
background-color: rgba(0, 0, 0, 0.02);
|
||||||
|
margin-left: 1rem;
|
||||||
|
padding: 0.5rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-item {
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-item:hover {
|
||||||
|
transform: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================
|
||||||
|
SKIP LINK (Accesibilidad)
|
||||||
|
============================================ */
|
||||||
|
|
||||||
|
.skip-link.screen-reader-text {
|
||||||
|
position: absolute;
|
||||||
|
left: -9999px;
|
||||||
|
top: 2.5em;
|
||||||
|
z-index: 100000;
|
||||||
|
padding: 1em 1.5em;
|
||||||
|
background-color: #0d6efd;
|
||||||
|
color: #fff;
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 600;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.skip-link.screen-reader-text:focus {
|
||||||
|
left: 6px;
|
||||||
|
outline: 3px solid rgba(13, 110, 253, 0.5);
|
||||||
|
outline-offset: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================
|
||||||
|
SITE CONTENT SPACING
|
||||||
|
============================================ */
|
||||||
|
|
||||||
|
.site-content {
|
||||||
|
margin-top: 2rem;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 767px) {
|
||||||
|
.site-content {
|
||||||
|
margin-top: 1rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================
|
||||||
|
WORDPRESS SPECIFIC CLASSES
|
||||||
|
============================================ */
|
||||||
|
|
||||||
|
/* WordPress Menu Classes */
|
||||||
|
.menu-item {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-item-has-children > .nav-link {
|
||||||
|
padding-right: 1.5rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Submenu Indicator (si se usan íconos) */
|
||||||
|
.menu-item-has-children > .nav-link::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
right: 0.5rem;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
border-left: 4px solid transparent;
|
||||||
|
border-right: 4px solid transparent;
|
||||||
|
border-top: 5px solid currentColor;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================
|
||||||
|
UTILITY CLASSES
|
||||||
|
============================================ */
|
||||||
|
|
||||||
|
/* Screen Reader Only Text */
|
||||||
|
.screen-reader-text {
|
||||||
|
border: 0;
|
||||||
|
clip: rect(1px, 1px, 1px, 1px);
|
||||||
|
clip-path: inset(50%);
|
||||||
|
height: 1px;
|
||||||
|
margin: -1px;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 0;
|
||||||
|
position: absolute;
|
||||||
|
width: 1px;
|
||||||
|
word-wrap: normal !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.screen-reader-text:focus {
|
||||||
|
background-color: #f1f1f1;
|
||||||
|
border-radius: 3px;
|
||||||
|
box-shadow: 0 0 2px 2px rgba(0, 0, 0, 0.6);
|
||||||
|
clip: auto !important;
|
||||||
|
clip-path: none;
|
||||||
|
color: #21759b;
|
||||||
|
display: block;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 700;
|
||||||
|
height: auto;
|
||||||
|
left: 5px;
|
||||||
|
line-height: normal;
|
||||||
|
padding: 15px 23px 14px;
|
||||||
|
text-decoration: none;
|
||||||
|
top: 5px;
|
||||||
|
width: auto;
|
||||||
|
z-index: 100000;
|
||||||
|
}
|
||||||
144
wp-content/themes/apus-theme/assets/js/main.js
Normal file
144
wp-content/themes/apus-theme/assets/js/main.js
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
/**
|
||||||
|
* Main JavaScript - APUS Theme
|
||||||
|
*
|
||||||
|
* Funcionalidades principales del tema según template del cliente.
|
||||||
|
* Incluye: Navbar sticky scroll effect y animaciones.
|
||||||
|
*
|
||||||
|
* @package Apus_Theme
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Navbar Scroll Effect
|
||||||
|
* Añade clase 'scrolled' al navbar cuando se hace scroll > 50px
|
||||||
|
*/
|
||||||
|
function initNavbarScrollEffect() {
|
||||||
|
const navbar = document.querySelector('.navbar');
|
||||||
|
|
||||||
|
if (!navbar) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optimización con throttle para mejor performance
|
||||||
|
let ticking = false;
|
||||||
|
|
||||||
|
function updateNavbar() {
|
||||||
|
if (window.scrollY > 50) {
|
||||||
|
navbar.classList.add('scrolled');
|
||||||
|
} else {
|
||||||
|
navbar.classList.remove('scrolled');
|
||||||
|
}
|
||||||
|
ticking = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('scroll', function() {
|
||||||
|
if (!ticking) {
|
||||||
|
window.requestAnimationFrame(updateNavbar);
|
||||||
|
ticking = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Ejecutar una vez al cargar por si la página ya tiene scroll
|
||||||
|
updateNavbar();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Highlight Active Menu Item
|
||||||
|
* Marca el item del menú correspondiente a la página actual
|
||||||
|
*/
|
||||||
|
function highlightActiveMenuItem() {
|
||||||
|
const currentUrl = window.location.href;
|
||||||
|
const navLinks = document.querySelectorAll('.navbar-nav .nav-link');
|
||||||
|
|
||||||
|
navLinks.forEach(function(link) {
|
||||||
|
// Remover active de todos
|
||||||
|
link.classList.remove('active');
|
||||||
|
|
||||||
|
// Agregar active si coincide URL
|
||||||
|
if (link.href === currentUrl) {
|
||||||
|
link.classList.add('active');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mobile Menu Close on Link Click
|
||||||
|
* Cierra el menú móvil automáticamente al hacer click en un enlace
|
||||||
|
*/
|
||||||
|
function initMobileMenuAutoClose() {
|
||||||
|
const navbarToggler = document.querySelector('.navbar-toggler');
|
||||||
|
const navbarCollapse = document.querySelector('.navbar-collapse');
|
||||||
|
const navLinks = document.querySelectorAll('.navbar-nav .nav-link');
|
||||||
|
|
||||||
|
if (!navbarToggler || !navbarCollapse) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
navLinks.forEach(function(link) {
|
||||||
|
link.addEventListener('click', function() {
|
||||||
|
// Solo en móvil (cuando el toggler es visible)
|
||||||
|
if (window.getComputedStyle(navbarToggler).display !== 'none') {
|
||||||
|
const bsCollapse = bootstrap.Collapse.getInstance(navbarCollapse);
|
||||||
|
if (bsCollapse) {
|
||||||
|
bsCollapse.hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Smooth Scroll for Anchor Links
|
||||||
|
* Scroll suave para enlaces ancla (#)
|
||||||
|
*/
|
||||||
|
function initSmoothScroll() {
|
||||||
|
const anchorLinks = document.querySelectorAll('a[href^="#"]');
|
||||||
|
|
||||||
|
anchorLinks.forEach(function(link) {
|
||||||
|
link.addEventListener('click', function(e) {
|
||||||
|
const targetId = this.getAttribute('href');
|
||||||
|
|
||||||
|
// Ignorar enlaces # vacíos o solo #
|
||||||
|
if (targetId === '#' || targetId === '') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const targetElement = document.querySelector(targetId);
|
||||||
|
|
||||||
|
if (targetElement) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
// Offset por el navbar sticky
|
||||||
|
const navbarHeight = document.querySelector('.navbar').offsetHeight;
|
||||||
|
const targetPosition = targetElement.getBoundingClientRect().top + window.pageYOffset - navbarHeight - 20;
|
||||||
|
|
||||||
|
window.scrollTo({
|
||||||
|
top: targetPosition,
|
||||||
|
behavior: 'smooth'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize all functions when DOM is ready
|
||||||
|
*/
|
||||||
|
function init() {
|
||||||
|
initNavbarScrollEffect();
|
||||||
|
highlightActiveMenuItem();
|
||||||
|
initMobileMenuAutoClose();
|
||||||
|
initSmoothScroll();
|
||||||
|
}
|
||||||
|
|
||||||
|
// DOM Ready
|
||||||
|
if (document.readyState === 'loading') {
|
||||||
|
document.addEventListener('DOMContentLoaded', init);
|
||||||
|
} else {
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
})();
|
||||||
@@ -166,6 +166,11 @@ if (is_admin()) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bootstrap Nav Walker
|
||||||
|
if (file_exists(get_template_directory() . '/inc/nav-walker.php')) {
|
||||||
|
require_once get_template_directory() . '/inc/nav-walker.php';
|
||||||
|
}
|
||||||
|
|
||||||
// Bootstrap and Script Enqueuing
|
// Bootstrap and Script Enqueuing
|
||||||
if (file_exists(get_template_directory() . '/inc/enqueue-scripts.php')) {
|
if (file_exists(get_template_directory() . '/inc/enqueue-scripts.php')) {
|
||||||
require_once get_template_directory() . '/inc/enqueue-scripts.php';
|
require_once get_template_directory() . '/inc/enqueue-scripts.php';
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* The header template file
|
* The header for our theme
|
||||||
*
|
*
|
||||||
* This template displays the site header including the opening HTML tags,
|
* Navbar sticky con Bootstrap 5.3.2 y animaciones según template del cliente.
|
||||||
* the site navigation, and the header content.
|
* Incluye: sticky positioning, gradient animations, responsive hamburger menu.
|
||||||
*
|
*
|
||||||
* @package Apus_Theme
|
* @package Apus_Theme
|
||||||
* @since 1.0.0
|
* @since 1.0.0
|
||||||
@@ -22,111 +22,77 @@
|
|||||||
<body <?php body_class(); ?>>
|
<body <?php body_class(); ?>>
|
||||||
<?php wp_body_open(); ?>
|
<?php wp_body_open(); ?>
|
||||||
|
|
||||||
<!-- Skip to main content link for accessibility -->
|
<!-- Skip to main content link para accesibilidad -->
|
||||||
<a class="skip-link screen-reader-text" href="#main-content">
|
<a class="skip-link screen-reader-text" href="#main-content">
|
||||||
<?php esc_html_e( 'Skip to content', 'apus-theme' ); ?>
|
<?php esc_html_e( 'Skip to content', 'apus-theme' ); ?>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<div id="page" class="site">
|
<div id="page" class="site">
|
||||||
|
|
||||||
<!-- Sticky Header -->
|
<!-- Navbar Sticky con Bootstrap 5 -->
|
||||||
<header id="masthead" class="site-header" role="banner">
|
<nav class="navbar navbar-expand-lg navbar-light bg-white py-3 border-bottom">
|
||||||
<div class="header-inner container">
|
<div class="container">
|
||||||
|
|
||||||
<!-- Site Branding / Logo -->
|
<!-- Logo / Site Title -->
|
||||||
<div class="site-branding">
|
<a class="navbar-brand" href="<?php echo esc_url( home_url( '/' ) ); ?>">
|
||||||
<?php
|
<?php
|
||||||
if ( has_custom_logo() ) :
|
if ( has_custom_logo() ) {
|
||||||
the_custom_logo();
|
the_custom_logo();
|
||||||
else :
|
} else {
|
||||||
?>
|
?>
|
||||||
<div class="site-identity">
|
<b><?php bloginfo( 'name' ); ?></b>
|
||||||
<?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; ?>
|
|
||||||
|
|
||||||
<?php
|
|
||||||
$description = get_bloginfo( 'description', 'display' );
|
|
||||||
if ( $description || is_customize_preview() ) :
|
|
||||||
?>
|
|
||||||
<p class="site-description"><?php echo esc_html( $description ); ?></p>
|
|
||||||
<?php endif; ?>
|
|
||||||
</div>
|
|
||||||
<?php
|
<?php
|
||||||
endif;
|
}
|
||||||
?>
|
?>
|
||||||
</div><!-- .site-branding -->
|
</a>
|
||||||
|
|
||||||
<!-- Desktop Navigation -->
|
<!-- Hamburger Toggle Button (Bootstrap 5) -->
|
||||||
<nav id="site-navigation" class="main-navigation desktop-nav" role="navigation" aria-label="<?php esc_attr_e( 'Primary Navigation', 'apus-theme' ); ?>">
|
<button class="navbar-toggler"
|
||||||
|
type="button"
|
||||||
|
data-bs-toggle="collapse"
|
||||||
|
data-bs-target="#navbarSupportedContent"
|
||||||
|
aria-controls="navbarSupportedContent"
|
||||||
|
aria-expanded="false"
|
||||||
|
aria-label="<?php esc_attr_e( 'Toggle navigation', 'apus-theme' ); ?>">
|
||||||
|
<span class="navbar-toggler-icon"></span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- Collapsible Menu -->
|
||||||
|
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||||
<?php
|
<?php
|
||||||
wp_nav_menu(
|
if ( has_nav_menu( 'primary' ) ) {
|
||||||
array(
|
wp_nav_menu(
|
||||||
'theme_location' => 'primary',
|
array(
|
||||||
'menu_id' => 'primary-menu',
|
'theme_location' => 'primary',
|
||||||
'menu_class' => 'primary-menu',
|
'container' => false,
|
||||||
'container' => false,
|
'menu_class' => 'navbar-nav ms-auto mb-2 mb-lg-0',
|
||||||
'fallback_cb' => false,
|
'fallback_cb' => false,
|
||||||
)
|
'depth' => 2,
|
||||||
);
|
'walker' => new WP_Bootstrap_Navwalker(),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// Fallback si no hay menú asignado
|
||||||
|
?>
|
||||||
|
<ul class="navbar-nav ms-auto mb-2 mb-lg-0">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="<?php echo esc_url( home_url( '/' ) ); ?>">
|
||||||
|
<?php esc_html_e( 'Home', 'apus-theme' ); ?>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="<?php echo esc_url( get_post_type_archive_link( 'post' ) ); ?>">
|
||||||
|
<?php esc_html_e( 'Blog', 'apus-theme' ); ?>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
?>
|
?>
|
||||||
</nav><!-- #site-navigation -->
|
</div>
|
||||||
|
|
||||||
<!-- Mobile Menu Toggle (Hamburger) -->
|
</div><!-- .container -->
|
||||||
<button
|
</nav><!-- .navbar -->
|
||||||
id="mobile-menu-toggle"
|
|
||||||
class="mobile-menu-toggle"
|
|
||||||
aria-controls="mobile-menu"
|
|
||||||
aria-expanded="false"
|
|
||||||
aria-label="<?php esc_attr_e( 'Toggle mobile menu', 'apus-theme' ); ?>"
|
|
||||||
>
|
|
||||||
<span class="hamburger-icon" aria-hidden="true">
|
|
||||||
<span class="line"></span>
|
|
||||||
<span class="line"></span>
|
|
||||||
<span class="line"></span>
|
|
||||||
</span>
|
|
||||||
<span class="screen-reader-text"><?php esc_html_e( 'Menu', 'apus-theme' ); ?></span>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
</div><!-- .header-inner -->
|
|
||||||
</header><!-- #masthead -->
|
|
||||||
|
|
||||||
<!-- Mobile Menu Overlay -->
|
|
||||||
<div id="mobile-menu-overlay" class="mobile-menu-overlay" aria-hidden="true"></div>
|
|
||||||
|
|
||||||
<!-- Mobile Navigation -->
|
|
||||||
<nav id="mobile-menu" class="mobile-menu" role="navigation" aria-label="<?php esc_attr_e( 'Mobile Navigation', 'apus-theme' ); ?>" aria-hidden="true">
|
|
||||||
<div class="mobile-menu-header">
|
|
||||||
<span class="mobile-menu-title"><?php esc_html_e( 'Menu', 'apus-theme' ); ?></span>
|
|
||||||
<button
|
|
||||||
id="mobile-menu-close"
|
|
||||||
class="mobile-menu-close"
|
|
||||||
aria-label="<?php esc_attr_e( 'Close menu', 'apus-theme' ); ?>"
|
|
||||||
>
|
|
||||||
<span aria-hidden="true">×</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<?php
|
|
||||||
wp_nav_menu(
|
|
||||||
array(
|
|
||||||
'theme_location' => 'primary',
|
|
||||||
'menu_id' => 'mobile-primary-menu',
|
|
||||||
'menu_class' => 'mobile-primary-menu',
|
|
||||||
'container' => false,
|
|
||||||
'fallback_cb' => false,
|
|
||||||
)
|
|
||||||
);
|
|
||||||
?>
|
|
||||||
</nav><!-- #mobile-menu -->
|
|
||||||
|
|
||||||
|
<!-- Main Content Area -->
|
||||||
<div id="content" class="site-content">
|
<div id="content" class="site-content">
|
||||||
|
|||||||
@@ -86,6 +86,34 @@ function apus_enqueue_header() {
|
|||||||
|
|
||||||
add_action('wp_enqueue_scripts', 'apus_enqueue_header', 10);
|
add_action('wp_enqueue_scripts', 'apus_enqueue_header', 10);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enqueue custom styles and main JavaScript
|
||||||
|
*/
|
||||||
|
function apus_enqueue_custom_assets() {
|
||||||
|
// Custom Styles - navbar animations and theme components
|
||||||
|
wp_enqueue_style(
|
||||||
|
'apus-custom-style',
|
||||||
|
get_template_directory_uri() . '/assets/css/custom-style.css',
|
||||||
|
array('apus-bootstrap'),
|
||||||
|
'1.0.0',
|
||||||
|
'all'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Main JavaScript - navbar scroll effects and interactions
|
||||||
|
wp_enqueue_script(
|
||||||
|
'apus-main-js',
|
||||||
|
get_template_directory_uri() . '/assets/js/main.js',
|
||||||
|
array('apus-bootstrap-js'),
|
||||||
|
'1.0.0',
|
||||||
|
array(
|
||||||
|
'in_footer' => true,
|
||||||
|
'strategy' => 'defer',
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
add_action('wp_enqueue_scripts', 'apus_enqueue_custom_assets', 11);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enqueue footer styles
|
* Enqueue footer styles
|
||||||
*/
|
*/
|
||||||
|
|||||||
200
wp-content/themes/apus-theme/inc/nav-walker.php
Normal file
200
wp-content/themes/apus-theme/inc/nav-walker.php
Normal file
@@ -0,0 +1,200 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Bootstrap 5 Nav Walker
|
||||||
|
*
|
||||||
|
* Custom Walker para wp_nav_menu() compatible con Bootstrap 5.
|
||||||
|
* Genera markup correcto para navbar, dropdowns y menús responsive.
|
||||||
|
*
|
||||||
|
* @package Apus_Theme
|
||||||
|
* @since 1.0.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Exit if accessed directly
|
||||||
|
if (!defined('ABSPATH')) {
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class WP_Bootstrap_Navwalker
|
||||||
|
*
|
||||||
|
* Bootstrap 5 compatible navigation menu walker
|
||||||
|
*/
|
||||||
|
class WP_Bootstrap_Navwalker extends Walker_Nav_Menu {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts the list before the elements are added.
|
||||||
|
*
|
||||||
|
* @param string $output Used to append additional content (passed by reference).
|
||||||
|
* @param int $depth Depth of menu item. Used for padding.
|
||||||
|
* @param stdClass $args An object of wp_nav_menu() arguments.
|
||||||
|
*/
|
||||||
|
public function start_lvl(&$output, $depth = 0, $args = null) {
|
||||||
|
if (isset($args->item_spacing) && 'discard' === $args->item_spacing) {
|
||||||
|
$t = '';
|
||||||
|
$n = '';
|
||||||
|
} else {
|
||||||
|
$t = "\t";
|
||||||
|
$n = "\n";
|
||||||
|
}
|
||||||
|
$indent = str_repeat($t, $depth);
|
||||||
|
|
||||||
|
// Dropdown menu classes
|
||||||
|
$classes = array('dropdown-menu');
|
||||||
|
|
||||||
|
$class_names = join(' ', apply_filters('nav_menu_submenu_css_class', $classes, $args, $depth));
|
||||||
|
$class_names = $class_names ? ' class="' . esc_attr($class_names) . '"' : '';
|
||||||
|
|
||||||
|
$output .= "{$n}{$indent}<ul$class_names>{$n}";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts the element output.
|
||||||
|
*
|
||||||
|
* @param string $output Used to append additional content (passed by reference).
|
||||||
|
* @param WP_Post $item Menu item data object.
|
||||||
|
* @param int $depth Depth of menu item. Used for padding.
|
||||||
|
* @param stdClass $args An object of wp_nav_menu() arguments.
|
||||||
|
* @param int $id Current item ID.
|
||||||
|
*/
|
||||||
|
public function start_el(&$output, $item, $depth = 0, $args = null, $id = 0) {
|
||||||
|
if (isset($args->item_spacing) && 'discard' === $args->item_spacing) {
|
||||||
|
$t = '';
|
||||||
|
$n = '';
|
||||||
|
} else {
|
||||||
|
$t = "\t";
|
||||||
|
$n = "\n";
|
||||||
|
}
|
||||||
|
$indent = ($depth) ? str_repeat($t, $depth) : '';
|
||||||
|
|
||||||
|
$classes = empty($item->classes) ? array() : (array) $item->classes;
|
||||||
|
$classes[] = 'menu-item-' . $item->ID;
|
||||||
|
|
||||||
|
// Add Bootstrap classes based on depth
|
||||||
|
if ($depth === 0) {
|
||||||
|
$classes[] = 'nav-item';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if menu item has children
|
||||||
|
$has_children = in_array('menu-item-has-children', $classes);
|
||||||
|
|
||||||
|
if ($has_children && $depth === 0) {
|
||||||
|
$classes[] = 'dropdown';
|
||||||
|
}
|
||||||
|
|
||||||
|
$class_names = join(' ', apply_filters('nav_menu_css_class', array_filter($classes), $item, $args, $depth));
|
||||||
|
$class_names = $class_names ? ' class="' . esc_attr($class_names) . '"' : '';
|
||||||
|
|
||||||
|
$id = apply_filters('nav_menu_item_id', 'menu-item-' . $item->ID, $item, $args, $depth);
|
||||||
|
$id = $id ? ' id="' . esc_attr($id) . '"' : '';
|
||||||
|
|
||||||
|
// Output <li>
|
||||||
|
if ($depth === 0) {
|
||||||
|
$output .= $indent . '<li' . $id . $class_names . '>';
|
||||||
|
} else {
|
||||||
|
$output .= $indent . '<li' . $class_names . '>';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Link attributes
|
||||||
|
$atts = array();
|
||||||
|
$atts['title'] = !empty($item->attr_title) ? $item->attr_title : '';
|
||||||
|
$atts['target'] = !empty($item->target) ? $item->target : '';
|
||||||
|
$atts['rel'] = !empty($item->xfn) ? $item->xfn : '';
|
||||||
|
$atts['href'] = !empty($item->url) ? $item->url : '';
|
||||||
|
|
||||||
|
// Add Bootstrap nav-link class for depth 0
|
||||||
|
if ($depth === 0) {
|
||||||
|
$atts['class'] = 'nav-link';
|
||||||
|
} else {
|
||||||
|
$atts['class'] = 'dropdown-item';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add dropdown-toggle class and attributes for parent items
|
||||||
|
if ($has_children && $depth === 0) {
|
||||||
|
$atts['class'] .= ' dropdown-toggle';
|
||||||
|
$atts['data-bs-toggle'] = 'dropdown';
|
||||||
|
$atts['aria-expanded'] = 'false';
|
||||||
|
$atts['role'] = 'button';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add active class for current menu item
|
||||||
|
if (in_array('current-menu-item', $classes) || in_array('current-menu-parent', $classes)) {
|
||||||
|
$atts['class'] .= ' active';
|
||||||
|
$atts['aria-current'] = 'page';
|
||||||
|
}
|
||||||
|
|
||||||
|
$atts = apply_filters('nav_menu_link_attributes', $atts, $item, $args, $depth);
|
||||||
|
|
||||||
|
$attributes = '';
|
||||||
|
foreach ($atts as $attr => $value) {
|
||||||
|
if (!empty($value)) {
|
||||||
|
$value = ('href' === $attr) ? esc_url($value) : esc_attr($value);
|
||||||
|
$attributes .= ' ' . $attr . '="' . $value . '"';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$title = apply_filters('the_title', $item->title, $item->ID);
|
||||||
|
$title = apply_filters('nav_menu_item_title', $title, $item, $args, $depth);
|
||||||
|
|
||||||
|
// Build the link
|
||||||
|
$item_output = $args->before;
|
||||||
|
$item_output .= '<a' . $attributes . '>';
|
||||||
|
$item_output .= $args->link_before . $title . $args->link_after;
|
||||||
|
$item_output .= '</a>';
|
||||||
|
$item_output .= $args->after;
|
||||||
|
|
||||||
|
$output .= apply_filters('walker_nav_menu_start_el', $item_output, $item, $depth, $args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Traverse elements to create list from elements.
|
||||||
|
*
|
||||||
|
* Display one element if the element doesn't have any children otherwise,
|
||||||
|
* display the element and its children. Will only traverse up to the max
|
||||||
|
* depth and no ignore elements under that depth. It is possible to set the
|
||||||
|
* max depth to include all depths, see walk() method.
|
||||||
|
*
|
||||||
|
* This method should not be called directly, use the walk() method instead.
|
||||||
|
*
|
||||||
|
* @param object $element Data object.
|
||||||
|
* @param array $children_elements List of elements to continue traversing (passed by reference).
|
||||||
|
* @param int $max_depth Max depth to traverse.
|
||||||
|
* @param int $depth Depth of current element.
|
||||||
|
* @param array $args An array of arguments.
|
||||||
|
* @param string $output Used to append additional content (passed by reference).
|
||||||
|
*/
|
||||||
|
public function display_element($element, &$children_elements, $max_depth, $depth, $args, &$output) {
|
||||||
|
if (!$element) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$id_field = $this->db_fields['id'];
|
||||||
|
|
||||||
|
// Display this element
|
||||||
|
if (is_object($args[0])) {
|
||||||
|
$args[0]->has_children = !empty($children_elements[$element->$id_field]);
|
||||||
|
}
|
||||||
|
|
||||||
|
parent::display_element($element, $children_elements, $max_depth, $depth, $args, $output);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Menu Fallback
|
||||||
|
*
|
||||||
|
* If this function is assigned to the wp_nav_menu's fallback_cb option
|
||||||
|
* and a menu has not been assigned to the theme location in the WordPress
|
||||||
|
* menu manager the function will display a basic menu of all published pages.
|
||||||
|
*
|
||||||
|
* @param array $args passed from the wp_nav_menu function.
|
||||||
|
*/
|
||||||
|
public static function fallback($args) {
|
||||||
|
if (current_user_can('edit_theme_options')) {
|
||||||
|
echo '<ul class="' . esc_attr($args['menu_class']) . '">';
|
||||||
|
echo '<li class="nav-item">';
|
||||||
|
echo '<a class="nav-link" href="' . esc_url(admin_url('nav-menus.php')) . '">';
|
||||||
|
esc_html_e('Crear un menú', 'apus-theme');
|
||||||
|
echo '</a>';
|
||||||
|
echo '</li>';
|
||||||
|
echo '</ul>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user