Site icon WP Smith

Add a Nagging Fixed Top Menu to Your Genesis Site

Recently, someone asked me to assist them with their nagging menu. Simply they wanted a menu that became fixed at the top after the user scrolled past the menu. In their case, they had a primary navigation menu at the top and then a secondary menu below the slider. So when the user scrolled past the slider to the store, the secondary menu would be fixed at the top as the user scrolled through the various store items. So I pointed them to an online tutorial by 1stwebdesigner.com (with example) that would help them get about 75% there. In some WordPress themes, this would get you all the way, but with Genesis, the JavaScript needed some massaging to be 100% correct. (NOTE: If you are reading this post on the single page, you can see this example on this page.)

The Script

First, let's review the script needed. I modified the script from 1stwebdesigner.com for Genesis themes.

jQuery(document).ready(function($) {
"use strict";
// Change #nav to #subnav for Genesis default Secondary Menu
var menu = $('#nav').find('.menu'),
pos = menu.offset();
// Add Default class
menu.addClass('default');
$(window).scroll(function(){
if($(this).scrollTop() > pos.top+menu.height() && menu.hasClass('default')){
menu.fadeOut('fast', function(){
$(this).removeClass('default').addClass('fixed').fadeIn('fast');
});
} else if($(this).scrollTop() <= pos.top && menu.hasClass('fixed')){
menu.fadeOut('fast', function(){
$(this).removeClass('fixed').addClass('default').fadeIn('fast');
});
}
});
});
view raw nagging-menu.js hosted with ❤ by GitHub

This script will make the primary menu appear at the top, but if you'd like the secondary menu to appear, then change #nav to #subnav. The rest is basic copy and paste. However, I recommend making two files: nagging-menu.js and nagging-menu.min.js.
jQuery(document).ready(function(e){"use strict";var t=e("#nav").find(".menu"),n=t.offset();t.addClass("default");e(window).scroll(function(){if(e(this).scrollTop()>n.top+t.height()&&t.hasClass("default")){t.fadeOut("fast",function(){e(this).removeClass("default").addClass("fixed").fadeIn("fast")})}else if(e(this).scrollTop()<=n.top&&t.hasClass("fixed")){t.fadeOut("fast",function(){e(this).removeClass("fixed").addClass("default").fadeIn("fast")})}})})

Now, I place these two files in my js folder which is found beside my images folder in my child theme. Some people can place this within a lib (for library) or inc (for includes) folder within their child theme. Whatever you prefer, but if you change the location, be sure to change the code in functions.php (below) to match your location.

Enqueuing Script

Next, you want WordPress to enqueue the script.

<?php
add_action( 'init', 'wps_register_nagging_script' );
/**
* Register Nagging script
*
* @uses CHILD_THEME_VERSION set this via wp_get_theme()->Version
* @link https://gist.github.com/4477270 Sets Child Theme Constants via wp_get_theme()
* @link https://gist.github.com/4083811 For jQuery alternative to be placed in footer
*/
function wps_nagging_script() {
$suffix = ( WP_DEBUG || SCRIPT_DEBUG ) ? '.js' : '.min.js';
wp_enqueue_script(
'nagging-menu',
get_stylesheet_directory_uri() . '/js/nagging-menu' . $suffix,
array( 'jquery' ),
CHILD_THEME_VERSION, // I set this via wp_get_theme()->Version, @link https://gist.github.com/4477270
true
);
}

In this function, I have a tertiary statement determining the suffix. For those of you who don't know what that is, it is a shortcut for an if-then block. For example, instead of this:
[php]
if ( WP_DEBUG || SCRIPT_DEBUG )
$suffix = '.js';
else
$suffix = '.min.js';
[/php]

We simply can write:
[php]
$suffix = ( WP_DEBUG || SCRIPT_DEBUG ) ? '.js' : '.min.js';
[/php]

This reads: "If WP_DEBUG or SCRIPT_DEBUG is true, then assign suffix variable to '.js' else assign the suffix variable to '.min.js'." So what then are WP_DEBUG or SCRIPT_DEBUG? These are WordPress constants for debugging, which all developers regardless of skill should have on while developing a site.

So, my functions-enqueue.php code enqueues the appropriate script based on whether WordPress has been optimized for output or for debugging (nothing is worse than trying to access a JavaScript file when debugging and the JS file being minimized).

However, this function enqueues this script globally on every page. Some, however, may want to not have the script on every page, so then you would register the script and enqueue it conditionally, as below.

<?php
add_action( 'init', 'wps_register_nagging_script' );
/**
* Register Nagging script
*
* @uses CHILD_THEME_VERSION set this via wp_get_theme()->Version
* @link https://gist.github.com/4477270 Sets Child Theme Constants via wp_get_theme()
* @link https://gist.github.com/4083811 For jQuery alternative to be placed in footer
*/
function wps_register_nagging_script() {
$suffix = ( WP_DEBUG || SCRIPT_DEBUG ) ? '.js' : '.min.js';
wp_register_script(
'nagging-menu',
get_stylesheet_directory_uri() . '/js/nagging-menu' . $suffix,
array( 'jquery' ),
CHILD_THEME_VERSION, // I set this via wp_get_theme()->Version, @link https://gist.github.com/4477270
true
);
}
add_action( 'wp_enqueue_scripts', 'wps_nagging_script' );
/**
* Enqueue Nagging script if on home/archive page
*/
function wps_nagging_script() {
if ( is_home() || is_front_page() || is_archive() || is_tax() )
wp_enqueue_script( 'nagging-menu' );
}

The Style

Minimally, you need this CSS to make this menu happen (though you don't really need the background possibly or the box-shadow properties).

#nav .fixed,
#subnav .fixed,
.fixed {
background: rgb(0,0,0); /* Fallback */
background: rgba(0,0,0,0.97); /* All modern browsers */
filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='#00000000', endColorstr='#00000000'); /* IE */
-webkit-box-shadow: 0 0 40px #222;
-moz-box-shadow: 0 0 40px #222;
box-shadow: 0 0 40px #222;
left: 0;
top: 0;
position: fixed;
width: 100%;
}
#nav .default,
#subnav .default,
.default {
}
view raw style.css hosted with ❤ by GitHub

You can do a whole lot here, just as 1stwebdesigner.com does, to fancy up the menu as it sits on top.