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
|
||||
if (file_exists(get_template_directory() . '/inc/enqueue-scripts.php')) {
|
||||
require_once get_template_directory() . '/inc/enqueue-scripts.php';
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<?php
|
||||
/**
|
||||
* The header template file
|
||||
* The header for our theme
|
||||
*
|
||||
* This template displays the site header including the opening HTML tags,
|
||||
* the site navigation, and the header content.
|
||||
* Navbar sticky con Bootstrap 5.3.2 y animaciones según template del cliente.
|
||||
* Incluye: sticky positioning, gradient animations, responsive hamburger menu.
|
||||
*
|
||||
* @package Apus_Theme
|
||||
* @since 1.0.0
|
||||
@@ -22,111 +22,77 @@
|
||||
<body <?php body_class(); ?>>
|
||||
<?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">
|
||||
<?php esc_html_e( 'Skip to content', 'apus-theme' ); ?>
|
||||
</a>
|
||||
|
||||
<div id="page" class="site">
|
||||
|
||||
<!-- Sticky Header -->
|
||||
<header id="masthead" class="site-header" role="banner">
|
||||
<div class="header-inner container">
|
||||
<!-- Navbar Sticky con Bootstrap 5 -->
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-white py-3 border-bottom">
|
||||
<div class="container">
|
||||
|
||||
<!-- Site Branding / Logo -->
|
||||
<div class="site-branding">
|
||||
<!-- Logo / Site Title -->
|
||||
<a class="navbar-brand" href="<?php echo esc_url( home_url( '/' ) ); ?>">
|
||||
<?php
|
||||
if ( has_custom_logo() ) :
|
||||
if ( has_custom_logo() ) {
|
||||
the_custom_logo();
|
||||
else :
|
||||
} else {
|
||||
?>
|
||||
<div class="site-identity">
|
||||
<?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>
|
||||
<b><?php bloginfo( 'name' ); ?></b>
|
||||
<?php
|
||||
endif;
|
||||
}
|
||||
?>
|
||||
</div><!-- .site-branding -->
|
||||
</a>
|
||||
|
||||
<!-- Desktop Navigation -->
|
||||
<nav id="site-navigation" class="main-navigation desktop-nav" role="navigation" aria-label="<?php esc_attr_e( 'Primary Navigation', 'apus-theme' ); ?>">
|
||||
<!-- Hamburger Toggle Button (Bootstrap 5) -->
|
||||
<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
|
||||
wp_nav_menu(
|
||||
array(
|
||||
'theme_location' => 'primary',
|
||||
'menu_id' => 'primary-menu',
|
||||
'menu_class' => 'primary-menu',
|
||||
'container' => false,
|
||||
'fallback_cb' => false,
|
||||
)
|
||||
);
|
||||
if ( has_nav_menu( 'primary' ) ) {
|
||||
wp_nav_menu(
|
||||
array(
|
||||
'theme_location' => 'primary',
|
||||
'container' => false,
|
||||
'menu_class' => 'navbar-nav ms-auto mb-2 mb-lg-0',
|
||||
'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) -->
|
||||
<button
|
||||
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 -->
|
||||
</div><!-- .container -->
|
||||
</nav><!-- .navbar -->
|
||||
|
||||
<!-- Main Content Area -->
|
||||
<div id="content" class="site-content">
|
||||
|
||||
@@ -86,6 +86,34 @@ function apus_enqueue_header() {
|
||||
|
||||
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
|
||||
*/
|
||||
|
||||
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