Create a Space theme for WordPress – 2021 – Part 5, Navigation

Table Of Contents

The authors portfolio site

Introduction – add a CSS folder and main.css file

In this WordPress navigation tutorial, we add a navigation bar to the header of the space theme. Additionally a mobile menu is created using CSS and Javascript.

First, create a folder named CSS, in the space theme folder, then create a file named main.css. This file will contain the styling for the menu.

Next, the file needs to be enqueued so that a link to it is placed in the header. Add the code below to the load_css() function in functions.php, make sure that it is below the Bootstrap enqueue function.

wp_register_style('main', get_template_directory_uri() . '/css/main.css', array(),false, 'all');
    wp_enqueue_style('main');

Procedure summary for the WordPress Navigation tutorial – Add a nav menu

1/ Add a menu location to the header file
2/ Register the location in the functions file.
3/ Style the menu in main.css

Add a menu location

To add a menu you need to add a menu location to the header file. Use the function wp_nav_menu() function. Further, this function has two parameters, in an array, the name of the registered theme location and an added CSS class. Naxt, the top-bar class is added to the unordered list element that forms the WordPress menu.

In short, make sure your header file looks as below, a WordPress title function has been added to display the page title in the browser tab.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title><?php wp_title(''); ?></title>
  <?php wp_head() ?>
</head>
<body>
<header>
 <div class="container">
  <?php 
  // nav area
   wp_nav_menu(
    array(
        'theme_location' => 'top-menu',
        'menu_class'=> 'top-bar'
     )
   )
   ?>
  </div>
</header>

Register the menu location in functions.php

Most importantly, In order for the menu system to show up in the backend, you need to add theme support for it in functions.php. Once this is done use the register_nav_menus() function to register the location name and handle. Here we are also registering a mobile menu location.

// Theme options
add_theme_support('menus');

//menus

register_nav_menus(
    array(
        'top-menu' => 'Top menu Location',
        'mobile-menu' => 'Mobile menu Location'
    )
)
?>

Style the menu

Once the initial styling is done your menu should look as below.

Now it’s time to style the menu using the main.css file we added earlier.

Below is an extract from the site’s page code. You can see all the ID’s and classes that WordPress applies to the menu. The main unordered list element has an Id of menu-all-pages, you can also see the top-bar class we added earlier.

The active page has a class of current-menu-item, added, this can be used to highlight the active menu button in CSS. Note the second level menu has a class of sub-menu and the containing li element has a class of menu-item-has-children.

 ........
<div class="menu-all-pages-container"><ul id="menu-all-pages" class="top-bar"><li id="menu-item-1644" class="menu-item menu-item-type-post_type menu-item-object-page current-menu-item page_item page-item-701 current_page_item menu-item-1644"><a href="http://spacetheme.test/front-page/" aria-current="page">Home</a></li>
<li id="menu-item-1643" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-1643"><a href="http://spacetheme.test/blog/">Blog</a></li>
<li id="menu-item-1645" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-has-children menu-item-1645"><a href="http://spacetheme.test/about/">About The Tests</a>
<ul class="sub-menu">
..........

First, style the header container using flexbox. This is used to align the menu horizontally and vertically.

header.container{
    display: flex;
    justify-content: center;
    align-items: center;  
    height: 100%

second, let’s style the UL element. In CSS the bullets are removed, as is padding and margins. Finally set display to flex, this turns any nested elements into flex items, forcing them to display horizontally.

header .top-bar{
    list-style-type: none;
    margin: 0;
    padding:0;
    display: flex;
}

Finally, stlye the links with some padding and then remove the left and right padding from the end elements.

header .top-bar li{
    position: relative;
}
header .top-bar li a{
    display: block;
    padding: 0.25rem 1rem;
    color: white;
}
header .top-bar li:first-child{
    padding-left: 0;
}
header .top-bar li:last-child{
    padding-right: 0;
}

Sub-menus and highlighting the active page

The sub menu will show all the time unless it is hidden. Therefore, the CSS below hides the sub menu and positions it so that it is just below the top-level button. Additionally, the Z-index setting makes sure that the menu is on top of any text.

/* 1st level sub menu */
header .top-bar li .sub-menu{
    z-index: 999;
    display: none;
    position: absolute;
    top: 100%;
    left:2em;
    background: white;
    margin: 0;
    padding:0;
    list-style-type: none;
    width: 250px;
    border: 1px solid black;
}

Add the CSS below to highlight the active button.

.current-menu-item{
    background-color: gray;
}

Next, style the links and show the menu on hover.

header .top-bar li .sub-menu a{
 color: black;  
 display: block;
}
header .top-bar li .sub-menu a:hover{
 color: green;  
}
header .top-bar .menu-item-has-children:hover .sub-menu{
Display:block;
}

Second level sub menus

if there are two levels of sub menu you need to deal with this in the CSS.

Add the code below, this hides the second level menu and then shows it when the first level button is hovered over.

/* 2nd level sub menu */
header .top-bar li .sub-menu .menu-item-has-children .sub-menu{
    display: none;
}
header .top-bar li .menu-item-has-children:hover .sub-menu {
Display:block;
}

Mobile menu

Rather than use a navwalker for Bootstrap, to add a mobile menu, here we do it manually. Consequently, a later tutorial will look at implementing the navwaker PHP class for Bootstrap menus.

The mobile menu used for this theme can handle two sub levels. As a result different colours and indents are used to indicate a sub level. A hamburger style button toggles the menu on and off. Media queries are used to control when the hamburger button is shown.

Moreover, the CSS is for multi-level menus is complex , however this is a good introduction to mobile menu design. Finally, Javascript is used to control the menu toggling.

Space theme mobile menu

At this point in the course, with the mobile menu in place, the entite main.css file should look as below.

header{
    Padding: 1rem;
    background: rgb(51, 48, 48);
    width: 100%;
}
.page-wrap{
     z-index: 998;
    padding: 2rem 0;
}
/* nav menu */
header.container{
    display: flex;
    justify-content: center;
    align-items: center;  
    height: 100%;
}
header .top-bar{
    list-style-type: none;
    margin: 0;
    padding:0;
    display: flex;
}
header .top-bar li{
    position: relative;
}
header .top-bar li a{
    display: block;
    padding: 0.25rem 1rem;
    color: white;
}
header .top-bar li:first-child{
    padding-left: 0;
}
header .top-bar li:last-child{
    padding-right: 0;
}
.current-menu-item{
    background-color: gray;
}
/* ................... large screen sub menus .............................*/
@media (min-width: 900px) {
    /* 1st level sub menu */
header .top-bar li .sub-menu{
    z-index: 1001;
    display: none;
    position: absolute;
    top: 100%;
    left:2em;
    background: white;
    margin: 0;
    padding:0;
    list-style-type: none;
    width: 250px;
    border: 1px solid black;
}
    header .top-bar li .sub-menu a{
    color: black;  
    display: block;
    }
    header .top-bar li .sub-menu a:hover{
    color: green;  
    }
    header .top-bar .menu-item-has-children:hover .sub-menu{
    Display:block;
    }
    /* 2nd level sub menu */
    header .top-bar li .sub-menu .menu-item-has-children .sub-menu{
        display: none;
    }
    header .top-bar li .menu-item-has-children:hover .sub-menu {
    Display:block;
    }
}
/* .................. mobile menu ................................. */
.burger{
    display: none;
}
.burger div{
    width: 25px;
    height: 3px;
    background-color: white;
    margin: 5px;
}
/* left padding keeps the burger to the right at 80% of the screen width */
    .burger{
        display:hidden;
        padding-left: 80vw;
        cursor: pointer;
    }
@media screen and (max-width:950px){
    body{
        overflow-x:hidden;
    }
    header .top-bar{
        z-index: 1200;
        position: absolute;
        right: -10vw;
        height: 92vh;
        width: 75%;
        top: 6vh;
        background-color: gray;
        display: flex;
        flex-direction: column;
        justify-content: center;
        transform: translateX(100%);
        /*transition: transform 0.2s ease-in;*/
    }
    .burger{
        display:block;
    }
    header .top-bar li .sub-menu{
        Background-color: blue;
        list-style-type: none;
        margin-left: 2em;
        padding: 0;
        
    }
     /* 2nd level sub menu */
    header .top-bar li .sub-menu .menu-item-has-children .sub-menu{
        Background-color: green;
        list-style-type: none;
    }
}
/* ...................end mobile menu........................*/

/* moves mobile menu into view, triggerd by javascript click action on hamburger .............*/
header .top-bar-active{
          transform: translateX(0%);
    }

The mobile menu “burger”

Here we create a “burger” icon just by using CSS . Firstly add the HTML below to the header file. This is just a set of empty divs.

 ..........
<div class="col-lg-2 burger">
      <div class="line1"> </div>
      <div class="line2"> </div>
      <div class="line3"> </div>
    </div>
......

Next, give the burger divs inside the burger class some width and height and make them white. Finally, hide the burger on large screens and give it a left padding of 80vw, that puts it 80% of the way to the right. Additionaly set the cursor to a pointer.

..........
.burger{
    display: none;
}
.burger div{
    width: 25px;
    height: 3px;
    background-color: white;
    margin: 5px;
}
/* left padding keeps the burger to the right at 80% of the screen width */
    .burger{
        display:hidden;
        padding-left: 80vw;
        cursor: pointer;
    }
........

The menu ul styling

The menu ul itself is styled below. Firstly, we set the position to absolue and set the height to be 92% of the view port. The top is positioned at 6% of the viewport to clear the header bar.

Secondly, the UL is set to a flex container and the flex direction is set to column to make the menu items into a vertcal column.

Most importantly translate x is used to push the menu off to the right so that it is not visible.

Finally javascript is used to slide the menu back in when the Burger is clicked.

....
 header .top-bar{
        z-index: 1200;
        position: absolute;
        right: -10vw;
        height: 92vh;
        width: 75%;
        top: 6vh;
        background-color: gray;
        display: flex;
        flex-direction: column;
        justify-content: center;
        transform: translateX(100%);
        /*transition: transform 0.2s ease-in;*/
    }
.........

Creating and enqueuing the javascript file

Create a folder in the theme folder named js. Inside this folder create a file named main.js and copy the code below into it.

const navSlide = () => {
    const burger = document.querySelector('.burger');
    const nav = document.querySelector('.top-bar');
    burger.addEventListener('click',()=>{
        nav.classList.toggle('top-bar-active');
    })
}
navSlide();

Fianally add the code below to the load_js function in functions.php.

wp_register_script('mainjs', get_template_directory_uri() . '/js/main.js' ,'jquery', false, true);
    wp_enqueue_script('mainjs');

The Javascript menu controller main.js

Refer to the main.js code above. Firstly a constant named navSlide is created that contains an anonymous function. Inside the function two other constants are created. One targets the burger and other the menu ul. To display and hide the menu a click event listener is added to the burger.

The event listener toggles a class named top-bar-active. As a result the x postion is set to 0%, sliding in the menu.

header .top-bar-active{
          transform: translateX(0%);
    }