• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 2473
  • Last Modified:

Mega Menu Without a Plugin in Wordpress, includes a loop if possible

Okay,
This is a doozie for me!
This is what I'm trying to achieve:

I have two custom post types: work and author each has a custom taxonomy called featured. I've managed to get two loops in each post type's archive page. One for "featured" and one for "all". Now I'm needing to create a mega menu that contiains this info, very much like the image below. My work around is to have a template called menu-author.php containing this loop and is hidden when the page loads but slides out from the navigation when the artists or album nav button is hovered?

 Mega menu example
I tried putting this code in a template and calling it from the header just to see if I could get the content to show up. I clearly am not doing this right because I get nothin. I'm not sure if I'm using the right query for the posts. I used the same code in my new template that I used in the custom post type archive page:

<div id="menu-featured"> 
	<h2>Featured</h2>
	<ul class="menu-list-o-items">
	<?php if ( have_posts() ) : ?>

	<?php /* Start the Loop */ ?>
	<?php $args = array( 'post_type' => 'writer', 'writer_featured' => 'featured', 'orderby'=>'title', 'order'=>'ASC', 'posts_per_page' => 4 );
		$loop = new WP_Query( $args ); ?>
	
	<?php while ( $loop->have_posts() ) : $loop->the_post(); ?>
			<?php echo '<li>'; ?>
			<a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
			<?php
		endwhile; ?>
		</ul>
	</div>
	<!-- end #menu-featured -->
		<?php rewind_posts(); ?>
	<div id="menu-all-items">
		<h2>All Authors</h2>
		<ul class="menu-list-o-items">
	<?php $args = array( 'post_type' => 'writer', 'orderby'=>'title', 'order'=>'ASC', 'posts_per_page' => 16 );
	$loop = new WP_Query( $args ); ?>
	
	<?php while ( $loop->have_posts() ) : $loop->the_post(); ?>
			<?php echo '<li>'; ?>
			<a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
			<?php 
	endwhile;  endif;?>
	</ul>
</div>
	<!-- end #all-items -->

Open in new window


This is some deep programming for me, but I'm up for the challenge...Cause I need to figure this out by Monday evening. Any help would be profoundly appreciated.
0
Alicia St Rose
Asked:
Alicia St Rose
  • 6
  • 5
1 Solution
 
jeremyjared74Commented:
How are you calling it? It should be like this:
If the file was named megamenu.php you would place the file in your themes root folder and in the header.php you would use:
<?php get_template_part('megamenu'); ?>

Open in new window


If that's how you're doing it let me know and I'll look for another solution. If you have more specific questions, let me know and I'll try to help.
0
 
Alicia St RoseOwner & Principle Developer/DesignerAuthor Commented:
Yay jeremyjared74 thanks.
Okay, this is how I was calling it:

<?php locate_template(array('author-menu.php', true) ); ?>

Open in new window


I tried your suggestion and I'm still not seeing anything.

Here's my header.php code:

<!DOCTYPE html>
<html <?php language_attributes(); ?>>
	<head>
		<meta http-equiv="content-type" content="<?php bloginfo('html_type'); ?>; charset=<?php bloginfo('charset'); ?>" />
		<title><?php wp_title(' | ', true, 'right'); ?><?php bloginfo('name'); ?></title>
		<link rel="stylesheet" type="text/css" href="<?php bloginfo('stylesheet_url'); ?>" />
		<?php if ( is_singular() ) wp_enqueue_script( 'comment-reply' ); ?>
		<?php wp_head(); ?>
	</head>
	<body <?php body_class(); ?>>
		<div id="wrapper" class="hfeed">
			<div id="header">
				<div id="masthead">
					<div id="branding">
						<div id="blog-title"><?php if ( is_singular() ) {} else {echo '<h1>';} ?><a href="<?php echo home_url() ?>/" title="<?php bloginfo( 'name' ) ?>" rel="home"><?php bloginfo( 'name' ) ?></a><?php if ( is_singular() ) {} else {echo '</h1>';} ?></div>
						</div>
						<?php if(is_front_page() OR is_singular('writer')) {
							echo '<h2 class="main-title">A Place for Girls to Connect</h2>';
							} else if(is_page()) {
							echo '<h2 class="main-title page-title">'; ?>
							<?php the_title(); ?>
							<?php echo '</h2>';
							} else if(is_post_type_archive('work')) {
							echo '<h2 class="main-title works-title">'; ?>
							<?php post_type_archive_title(' ', true); ?>
							<?php echo '</h2>'; 
							} else if(is_post_type_archive('writer')) {
							echo '<h2 class="main-title authors-title">'; ?>
							<?php post_type_archive_title(' ', true); ?>
							<?php echo '</h2>';
							}?>
					<div id="nav">
						<?php wp_nav_menu( array( 'theme_location' => 'main-menu' ) ); ?>
						<?php get_template_part('megamenu'); ?>
					</div>
						
						
				</div>
			</div>
		<div id="main">

Open in new window

0
 
jeremyjared74Commented:
OK, here's what I ended up using to get the menu to only show if it is on the custom post type page. I hope I can explain this right.

The Theory:

1.) I've created a custom menu and named it megamenu.php and uploaded it to my server in the root of my themes folder.

2.) Next I created the custom menu in my themes functions.php file and gave it the name and location "megamenu".

3.) I created a somewhat messy conditional statement so that the menu only shows when viewing the custom post type (in this case "writer". Placed the code in the header.php wrapped in a div for separate styling.

4.) Went to the Appearance>Menu's section of the WP Admin panel and created a menu for the custom menu I just added and placed the custom post type pages/posts in the order I wanted and saved it.

Here is the code for your theme and the steps I took-
1.) The megamenu.php
<?php wp_nav_menu( array( 
  'theme_location' => 'megamenu', 
  )); 
?>

Open in new window

NOTE:
This probably could have been done in the functions.php file, but I was already heading down this road with a different solution when I thought of using a custom menu, so I just went with it.

2.)
The Custom Menu Code for functions.php:
add_action( 'init', 'register_my_menus' );
  function register_my_menus() {
    register_nav_menus(
      array(
        'main' => __( 'main' ), //This already existed (my default menu function)
        'portfolio' => __( 'megamenu' ),//This already existed (I changed from Secondary to megamenu)
        'tertiary-menu' => __( 'Tertiary Menu' )//This already existed (my default menu function)
        ));
    }

Open in new window


NOTE:
In the themes I build I always register 3 menu's even though I usually only use one of them. So the code above is just my regular 3 menu function with the second menu item changed to megamenu. If you have a theme that uses the wp-nav menu system, just add this to the existing array:        
 'main' => __( 'main' ), 

Open in new window


3.)
The Conditional Statement for the header.php that only shows the menu when viewing a custom post type:
<div id="author-menu">
<?php
$queried_post_type = get_query_var('post_type');
if ( is_paged() && 'writer' ==  $queried_post_type ) {
  get_template_part('author-menu');
}

$queried_post_type = get_query_var('post_type');
if ( is_single() && 'writer' ==  $queried_post_type ) {
  get_template_part('author-menu');
}
$queried_post_type = get_query_var('post_type');
if ( is_page('writer')) {
  get_template_part('megamenu');
}
?>
</div>

Open in new window


NOTE:
You might not need all three instances above. The first part "is_paged" is just there in case you are using archived post_types, the second "is_single" is for viewing single custom_post_type, and the final section is for the static page that is used to display the custom post types (in my themes I commonly add a Portfolio post_type. I then create a custom page that displays the portfolio items). In my case I have a page named Portfolio, so where it says is_page('writer'), it would be is_page('portfolio') for me since that is what I name the static page I create. I put "writer" on yours, but you will need to change it to the actual name for the page you have created (if that's what you do also).

HERE IS THE CODE FOR THE HEADER.PHP FILE YOU PROVIDED:
<!DOCTYPE html><html <?php language_attributes(); ?>>

<head>
  <meta http-equiv="content-type" content="<?php bloginfo('html_type'); ?>; charset=<?php bloginfo('charset'); ?>" />
    <title><?php wp_title(' | ', true, 'right'); ?><?php bloginfo('name'); ?></title>
    <link rel="stylesheet" type="text/css" href="<?php bloginfo('stylesheet_url'); ?>" />
  <?php if ( is_singular() ) wp_enqueue_script( 'comment-reply' ); ?>
  <?php wp_head(); ?>
</head>
  
<body <?php body_class(); ?>>
  <div id="wrapper" class="hfeed">
    <div id="header">
      <div id="masthead">
        <div id="branding">
          <div id="blog-title"><?php if ( is_singular() ) {} else {echo '<h1>';} ?>
          <a href="<?php echo home_url() ?>/" title="<?php bloginfo( 'name' ) ?>" rel="home"><?php bloginfo( 'name' ) ?></a>
          <?php if ( is_singular() ) {} else {echo '</h1>';} ?></div>
        </div>
          <?php 
            if( is_front_page() OR is_singular('writer')) {
              echo '<h2 class="main-title">A Place for Girls to Connect</h2>';
              } else if(is_page()) {
              echo '<h2 class="main-title page-title">'; 
                the_title();
              echo '</h2>';
              } else if(is_post_type_archive('work')) {
              echo '<h2 class="main-title works-title">'; 
                post_type_archive_title(' ', true); 
              echo '</h2>'; } else if(is_post_type_archive('writer')) {
              echo '<h2 class="main-title authors-title">'; 
                post_type_archive_title(' ', true); 
              echo '</h2>'; 
                } ?>
        <div id="nav">
        <?php wp_nav_menu( array( 'theme_location' => 'main-menu' ) ); ?>
        </div> 
        
        
    <!-- @@@@@@@@ THIS CAN BE SIMPLIFIED INTO A STRING LIKE ABOVE (I WAS IN A RUSH) @@@@@@@@ -->
    
        <div id="author-menu">
        <?php
          $queried_post_type = get_query_var('post_type');
            if ( is_paged() && 'writer' ==  $queried_post_type ) {
              get_template_part('author-menu');
              }
          
          $queried_post_type = get_query_var('post_type');
            if ( is_single() && 'writer' ==  $queried_post_type ) {
              get_template_part('author-menu');
              }
          $queried_post_type = get_query_var('post_type');
            if ( is_page('writer')) {
              get_template_part('megamenu');
              }
          ?>
        </div>
        
    <!-- @@@@@@@@ END MY GREAT BIG GOB OF CODE (BUT IT WORKS :) @@@@@@@ -->
        
                
      </div>
    </div>
<div id="main">

Open in new window

0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
jeremyjared74Commented:
I messed up and didn't change the menu for step 2. It should be this:
add_action( 'init', 'register_my_menus' );
  function register_my_menus() {
    register_nav_menus(
      array(
        'main' => __( 'main' ),  //This already existed (my default menu function)
        'megamenu' => __( 'megamenu' ), //This already existed (I changed from Secondary to megamenu)
        'tertiary-menu' => __( 'Tertiary Menu' ), //This already existed (my default menu function)
        ));
    }

Open in new window

0
 
Alicia St RoseOwner & Principle Developer/DesignerAuthor Commented:
Hi Jeremyjared74, this is awesome!
But hopefully my vagueness didn't cause you to do extra work. I need the menu to show up on all pages and posts, throughout the entire site. It comes off the primary menu as a horizonal slideout type of thing. Wish I could show you, but it's one of those NDA things...
I might even be able to figure that out from your code.
I'm so grateful for your help!
0
 
Alicia St RoseOwner & Principle Developer/DesignerAuthor Commented:
So also to clarify, the menu should appear when the navigation button 'Writers'  is hovered over anywhere in the site.
This is basic jquery, so I should be able to figure that out...
0
 
jeremyjared74Commented:
No problem, I learned something while figure this out. In the case that it will show on all pages, just replace the conditional statement (STEP 3) and replace it with this in header.php:

Option 1:
Just use
<?php wp_nav_menu( array( 
  'theme_location' => 'megamenu', 
  )); 
?>

Open in new window

In the option above, just go to step 2 to add the new menu to your functions.php file, then maybe wrap the code above in a div to allow more control over the styling if needed.

Option 2:
Create a file named megamenu.php and place this code, in it and add it to the root of your theme folder:
<?php wp_nav_menu( array( 
  'theme_location' => 'megamenu', 
  )); 
?>

Open in new window


Then in the header.php file use this to call the menu:
<?php get_template_part( 'megamenu' ); ?>

Open in new window


The last step is to add a new menu in the Admin Panel eg; Appearance>Menu's>Add Menu, then add your custom post type posts and save it. Then you just need to style it as required.

Let me know if you have any questions.
Regards,
JeremyJared74
0
 
Alicia St RoseOwner & Principle Developer/DesignerAuthor Commented:
okay more,
The content in this menu should be dynamically generated using the loop? At least that is what I was attempting to do. I wanted to display a mini archive in the mega menu. If that's possible. If not, then this plan B will do and folks will have to manually adjust the menus when they enter new posts
0
 
jeremyjared74Commented:
OK I've been working on this to output the post_type menu dynamically:

<?php
function wp_list_post_types( $args ) {
    $defaults = array(
        'numberposts'  => -1,
        'offset'       => 0,
        'orderby'      => 'menu_order, post_title',
        'post_type'    => 'writer',
        'depth'        => -1,
        'show_date'    => '',
        'date_format'  => get_option('date_format'),
        'child_of'     => 0,
        'exclude'      => '',
        'include'      => '',
        'title_li'     => __(''),
        'echo'         => 1,
        'link_before'  => '',
        'link_after'   => '',
        'exclude_tree' => '' );
  $r = wp_parse_args($args, $defaults);
  extract($r, EXTR_SKIP);
  $output = '';
  $current_page = 0;
  $r['exclude'] = preg_replace('/[^0-9,]/', '', $r['exclude']);
  $exclude_array = ($r['exclude']) ? explode(',', $r['exclude']) : array();
  $r['exclude'] = implode(',', apply_filters('wp_list_post_types_excludes', $exclude_array));
  $r['hierarchical'] = 0;
  $pages = get_posts($r);
  if (!empty($pages)) {
      if ($r['title_li'])
          $output .= '<li class="navigation">' . $r['title_li'] . '<ul>';
      global $wp_query;
      if (($r['post_type'] == get_query_var('post_type')) || is_attachment())
          $current_page = $wp_query->get_queried_object_id();
      $output .= walk_page_tree($pages, $r['depth'], $current_page, $r);
      if ($r['title_li'])
          $output .= '</ul></li>';
  }
  $output = apply_filters('wp_list_pages', $output, $r);
  if ($r['echo'])
      echo $output;
  else
      return $output;
  }
?>

Open in new window


It isn't working exactly as planned but it's a good start. A few customizations and it should work fine. It's showing the menu items now, but I'm having a bit of trouble matching the wp nav menu that I already have. Worst case scenario you would have to re-style this menu from scratch to match your current one.

The code above goes in your functions.php file.

This goes in the header.php:
<?php wp_list_post_types('writer'); ?>

Open in new window

I'm sure you can add more post_types to that if needed, or use an array to add some args to it. I only have one post type set up so I didn't test it on multiple ones.

Just ditch everything before this post if you want to use dynamic menu (not wp_nav's).

I've been working on getting the wp_nav_menu to auto-populate page/post order, but I've hit a few glitches. It would be nice to have the best of both worlds. I'm getting closer to a solution, maybe soon I'll have it?
0
 
Alicia St RoseOwner & Principle Developer/DesignerAuthor Commented:
Hi jeremyjared74,
This is working for me. I don't think I emphasized very well, that I need the posts with the featured taxonomy in the left column and that they must also show up in amongst all the rest in the right column.
I went back to trying to use my loop with rewind posts and I realize that I'd left off the closing
<?php else: ?><?php endif; ?>

Open in new window

So right now I've got this and it's working:

<div id="mega-menu-authors">
						<p>Featured</p>

							<ul>
				<?php if ( have_posts() ) : ?>

				<?php /* Start the Loop */ ?>
				<?php $args = array( 'post_type' => 'writer', 'writer_featured' => 'featured', 'orderby'=>'title', 'order'=>'ASC', 'posts_per_page' => 4 );
					$loop = new WP_Query( $args ); ?>
  			
				<?php while ( $loop->have_posts() ) : $loop->the_post(); ?>
						<?php echo '<li>'; ?>
						<a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
						<?php echo '</li>';
					endwhile; ?>
					</ul>
				</div>
				<!-- end #featured -->
					<?php rewind_posts(); ?>
					<div>
					<h2>All Authors</h2>
					<ul>
				<?php $args = array( 'post_type' => 'writer', 'orderby'=>'title', 'order'=>'ASC', 'posts_per_page' => 16 );
				$loop = new WP_Query( $args ); ?>
			
			<?php while ( $loop->have_posts() ) : $loop->the_post(); ?>
						<?php echo '<li>'; ?>
						<a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
						<?php echo '</li>';
				endwhile; ?>
				<li><a href="<?php bloginfo('url'); ?>/authors">View all</a></li>
				</ul>
				</div>
				<!-- end #all-items -->			
				<?php else : ?>
				<?php endif ?>
			</div>

Open in new window


I need to do it twice though, as I have to have another mega menu for works (book titles), which should be hidden on page load and slide out when the "Works" nav button is hovered..
In reality this isn't really a menu, it's a loop stuck in a div with absolute positioning and some jQuery (which I'm hoping I can pull off). It feels like a hack to me. If you have something more elegant coming. I'd rather use it and learn a thing or two. If it becomes vastly complicated, this option will do.
0
 
Alicia St RoseOwner & Principle Developer/DesignerAuthor Commented:
I decided to go with the loop option. It gets the job done.
Thank you for all of your help Jeremyjared74!
0

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

  • 6
  • 5
Tackle projects and never again get stuck behind a technical roadblock.
Join Now