• Resolved Agence Myso

    (@agence-myso)


    Hi everyone,

    I am totally lost…
    I am trying to build a three levels menu based on categories.
    The problem is that it has to be built in a way that the owner of the site will be able to add categories and custom post types on the frontend without going to the appearance -> menus section.
    I use wp_list_categories to display the parent categories. Then, I am using get_the_category to to display categories list outside the loop. Last level, I use get_posts to retrieve posts info.
    Firstly, it doesn’t work. I only get parent categories and posts.
    Secondly, this scheme won’t allow me to add a css class to active items and so give the frontend user the ability to know where he is.
    Does anyone has an idea of how to build such a menu system in WordPress?
    Thanks!

    Here is my code :

    <div class="navigation col-lg-4 col-md-4 col-xs-4">
    
    		<div class="col-lg-4 col-md-4 col-xs-12">
    
    			<?php
    			    $args = array(
    				'show_option_all'    => '',
    				'orderby'            => 'name',
    				'order'              => 'ASC',
    				'style'              => 'none',
    				'show_count'         => 0,
    				'hide_empty'         => 0,
    				'use_desc_for_title' => 1,
    				'child_of'           => 0,
    				'feed'               => '',
    				'feed_type'          => '',
    				'feed_image'         => '',
    				'exclude'            => 1,
    				'exclude_tree'       => '',
    				'include'            => '',
    				'hierarchical'       => 1,
    				'title_li'           => __( 'Categories' ),
    				'show_option_none'   => __( 'No categories' ),
    				'number'             => null,
    				'echo'               => 1,
    				'depth'              => 1,
    				'current_category'   => 0,
    				'pad_counts'         => 0,
    				'taxonomy'           => 'category',
    				'walker'             => null
    			    );
    			    wp_list_categories( $args );
    			?>
    		</div>
    
    		<div class="col-lg-4 col-md-4 col-xs-12">
    
    				<?php
    
    		$categories = get_the_category();
    
    			if ($categories) {
    
    				$category_id = $categories[0]->cat_ID;
    
    			} else {
    
    				$all_cats = get_categories();
    
    				foreach ($all_cats as $value) {
    
    					if(is_category( $value->slug )) {
    						$category_id = $value->cat_ID;
    
    					}
    				}
    		}
    
    		if (isset($category_id)): 
    
    			$category_id = get_the_category();
    			$separator = ' ';
    			$output = '';
    			foreach ($category_id as $category_link) {
    				$output .= '<a href="'.get_category_link( $category_link->term_id ).'" title="' . esc_attr( sprintf( __( "View all posts in %s" ), $category_link->name ) ) . '">'.$category->cat_name.'</a>'.$separator;
    			}
    			echo trim($output, $separator);
    
    			    $videos = array(
    				'posts_per_page' => 99,
    				'post_type' => 'video',
    				'orderby' => 'menu_order',
    				'order' => 'DESC'
    			);
    
    			$cat_posts = get_posts( $videos );
    
    				foreach ( $cat_posts as $post ) : setup_postdata( $post ); 
    
    			?>
    						<li><a href="<?php the_permalink(); ?>">
    						<?php the_title(); ?>
    						</a>
    						</li>	
    
    			<?php endforeach; wp_reset_postdata();
    			endif;
    			?>
    
    		</div>
    
    		<div class="col-lg-4 col-md-4 col-xs-12">
    		</div>
    
    	</div>

Viewing 15 replies - 1 through 15 (of 22 total)
  • Firstly, it doesn’t work. I only get parent categories and posts.

    It looks like you’re setting the depth to 1, which only looks at the first level.

    Your options are:

    • 0 – All Categories and child Categories (Default).
    • -1 – All Categories displayed in flat (no indent) form (overrides hierarchical).
    • 1 – Show only top level Categories
    • n – Value of n (some number) specifies the depth (or level) to descend in displaying Categories

    Secondly, this scheme won’t allow me to add a css class to active items and so give the frontend user the ability to know where he is.

    Are you trying to show which post the user is on or which category they are in?

    Are you building a menu that is going to be the main menu to navigate between videos? I ask, because if you have, for example, 5 categories with up to 99 videos (limit you set), that’s a menu with almost 500 items– is that right?

    Thread Starter Agence Myso

    (@agence-myso)

    Thank you Ryan for your time!
    That is right. If you want to see the previous version of the site, you can go here : https://www.supergrafic.com. You will have the what was built with flash and I am trying to rebuild with wp to give better admin access to my client.

    I have already done things like that : https://www.alexandresaltiel.com, but, it only needed two levels categories menus. Here I need three, which causes me headaches.

    Since I posted the message, I have thought of something else : calling the parent categories (the same way as it was in my message), then adding a menu for subcategories in a second div with wp-nav-menu, then, retrieving the posts list in a third div with the loop. But I can’t figure out how to get post list for each subcategories… It must be easy but I’m kind of stuck on this problem…

    If you get all categories (using one of the methods described above), you’ll have access to every single category ID. Using this ID, you can then set that as an argument when calling get_posts.

    $videos = array(
    	'category' => $category_id,
    	'posts_per_page' => 99,
    	'post_type' => 'video',
    	'orderby' => 'menu_order',
    	'order' => 'DESC'
    );
    Thread Starter Agence Myso

    (@agence-myso)

    Yes sure,

    BUT, my problem is:
    When you click on a category, you go on this category page. Doing this, you loose the category list.
    More explicitly, when you click on on the parent category, you go on category 21 archive page. There, you have the category list. But as soon as you click on a subcategory, the categories disappear, because you are entering another category archive page (let’s say cat=5). I am trying to build an if statement (if (is_category(21)), but I also need to to have OR if parent_category == 21. And this I don’t know how to do it in WP…

    Thread Starter Agence Myso

    (@agence-myso)

    It will be clearer with the code (my problem is on line 39) :

    <div class="navigation col-lg-4 col-md-4 col-xs-4">
    
    		<div class="col-lg-4 col-md-4 col-xs-12">
    
    			<?php
    			    $args = array(
    				'show_option_all'    => '',
    				'orderby'            => 'name',
    				'order'              => 'ASC',
    				'style'              => 'none',
    				'show_count'         => 0,
    				'hide_empty'         => 0,
    				'use_desc_for_title' => 1,
    				'child_of'           => 0,
    				'feed'               => '',
    				'feed_type'          => '',
    				'feed_image'         => '',
    				'exclude'            => 1,
    				'exclude_tree'       => '',
    				'include'            => '',
    				'hierarchical'       => 1,
    				'title_li'           => __( 'Categories' ),
    				'show_option_none'   => __( 'No categories' ),
    				'number'             => null,
    				'echo'               => 1,
    				'depth'              => 1,
    				'current_category'   => 0,
    				'pad_counts'         => 0,
    				'taxonomy'           => 'category',
    				'walker'             => null
    			    );
    			    wp_list_categories( $args );
    			?>
    		</div>
    
    		<div class="col-lg-4 col-md-4 col-xs-12">
    
    		<?php
    
    		$categories = get_the_category();
    
    			if ($categories) {
    
    				$category_id = $categories[0]->cat_ID;
    
    			} else {
    
    				$all_cats = get_categories();
    
    				foreach ($all_cats as $value) {
    
    					if(is_category( $value->slug )) {
    						$category_id = $value->cat_ID;
    
    					}
    				}
    			}
    
    		if (is_category(21) OR $all_cats->category_parent == 21): 
    
    		$defaults = array(
    				'theme_location'  => '',
    				'menu'            => 'video_categories',
    				'container'       => 'div',
    				'container_class' => '',
    				'container_id'    => '',
    				'menu_class'      => 'menu',
    				'menu_id'         => '',
    				'echo'            => true,
    				'fallback_cb'     => 'wp_page_menu',
    				'before'          => '',
    				'after'           => '',
    				'link_before'     => '',
    				'link_after'      => '',
    				'items_wrap'      => '<ul id="%1$s" class="%2$s">%3$s</ul>',
    				'depth'           => 0,
    				'walker'          => ''
    			);
    
    		wp_nav_menu( $defaults ); ?>
    
    		</div>
    
    	<div class="col-lg-4 col-md-4 col-xs-12">
    
    		<?php 
    
    		if (isset($category_id)):
    
    			    $videos = array(
    				'posts_per_page' => 99,
    				'post_type' => 'video',
    				'category' => $category_id,
    				'orderby' => 'menu_order',
    				'order' => 'DESC'
    			);
    
    			$cat_posts = get_posts( $videos );
    
    				foreach ( $cat_posts as $post ) : setup_postdata( $post ); 
    
    			?>
    						<li><a href="<?php the_permalink(); ?>">
    						<?php the_title(); ?>
    						</a>
    						</li>	
    
    			<?php endforeach; wp_reset_postdata();
    			endif;
    			?>
    		</div>
    
    	<?php endif; ?>
    	</div>

    I don’t see that get_the_category being called in the WordPress loop. If it’s outside the loop, it needs a post ID.

    Thread Starter Agence Myso

    (@agence-myso)

    That’s right…
    I finally succeeded in building my three columns menu.
    Next problem is how to put some CSS on active items. Let’s say : you are in “video” section, under the category “clips” and you choose to watch clip n°1.
    Do you have an idea of how to highlight each item and keep them highlighted?

    You’re looking for a way to track which video the user watched, i.e., which page the user visited? Is this user logged in or anonymous? Does it need to remain highlighted after their current session ends and they come back later?

    (If you can, share the code that ended up working for you, so that if others have this problem, they can benefit from the solution, too.)

    Thread Starter Agence Myso

    (@agence-myso)

    Ok, so, I need users (anonymous users) to know in which parent / category they are and which video they are looking at. It needs a class “active” on three levels ate the same time. I guess it can be done with something like get_categories and get_categories->parent, but I can’t figure it out clearly right now…
    Here is my code :

    <div class="navigation col-lg-4 col-md-4 col-xs-4">
    
    		<div class="col-lg-4 col-md-4 col-xs-12">
    
    			<?php
    			    $args = array(
    				'show_option_all'    => '',
    				'orderby'            => 'name',
    				'order'              => 'ASC',
    				'style'              => 'none',
    				'show_count'         => 0,
    				'hide_empty'         => 0,
    				'use_desc_for_title' => 1,
    				'child_of'           => 0,
    				'feed'               => '',
    				'feed_type'          => '',
    				'feed_image'         => '',
    				'exclude'            => 1,
    				'exclude_tree'       => '',
    				'include'            => '',
    				'hierarchical'       => 1,
    				'title_li'           => __( 'Categories' ),
    				'show_option_none'   => __( 'No categories' ),
    				'number'             => null,
    				'echo'               => 1,
    				'depth'              => 1,
    				'current_category'   => 0,
    				'pad_counts'         => 0,
    				'taxonomy'           => 'category',
    				'walker'             => null
    			    );
    			    wp_list_categories( $args );
    			?>
    		</div>
    
    		<div class="col-lg-4 col-md-4 col-xs-12">
    
    		<?php
    
    		if ( is_category() ) {
    		  $cat = get_query_var('cat');
    		  $args = array(
    		    'include' => $cat,
    			  'hide_empty' => 0
    			  );
    		  $categories = get_categories($args);
    		  if ( ($cat == 21) || ($categories[0]->category_parent == 21) ) :
    
    		$defaults = array(
    				'theme_location'  => '',
    				'menu'            => 'video_categories',
    				'container'       => 'div',
    				'container_class' => '',
    				'container_id'    => '',
    				'menu_class'      => 'menu',
    				'menu_id'         => '',
    				'echo'            => true,
    				'fallback_cb'     => 'wp_page_menu',
    				'before'          => '',
    				'after'           => '',
    				'link_before'     => '',
    				'link_after'      => '',
    				'items_wrap'      => '<ul id="%1$s" class="%2$s">%3$s</ul>',
    				'depth'           => 0,
    				'walker'          => ''
    			);
    
    		wp_nav_menu( $defaults ); ?>
    
    		</div>
    
    	<div class="col-lg-4 col-md-4 col-xs-12">
    
    		<?php 
    
    		$categories = get_the_category();
    
    			if ($categories) {
    
    				$category_id = $categories[0]->cat_ID;
    
    			} else {
    
    				$all_cats = get_categories();
    
    				foreach ($all_cats as $value) {
    
    					if(is_category( $value->slug )) {
    						$category_id = $value->cat_ID;
    
    					}
    				}
    			}
    
    		if (isset($category_id)):
    
    			    $videos = array(
    				'posts_per_page' => 99,
    				'post_type' => 'video',
    				'category' => $category_id,
    				'orderby' => 'menu_order',
    				'order' => 'DESC'
    			);
    
    			$cat_posts = get_posts( $videos );
    
    				foreach ( $cat_posts as $post ) : setup_postdata( $post ); 
    
    			?>
    						<li><a href="<?php the_permalink(); ?>">
    						<?php the_title(); ?>
    						</a>
    						</li>	
    
    			<?php endforeach; wp_reset_postdata();
    			endif;
    			?>
    		</div>
    
    <?php endif; } ?>
    	</div>

    Thread Starter Agence Myso

    (@agence-myso)

    WOW! WordPress is brilliant!
    I just found that if you call to wp_list_categories as a list (‘style’ => ‘list’), you get some very cool css classes : ‘current-cat’ and ‘current-cat-parent’ !!
    This way I can already highlight two levels : parent category and subcategory. Now the only thing left to be done is highlight the current post in the list and I’m done!

    Good work on finding that! If all that remains is highlighting the one the user is currently on, you should have access to the global $post if you include a statement like this:

    global $post;

    Then you can compare the current post ID ($post->ID) to the one currently being printed out in your foreach loop. If the IDs match, you can add a class of your own to the <li>, for example.

    I do see that you’re using $post in your code (that doesn’t refer to the global one), so you’ll want to rename that to something else so it doesn’t conflict with the global $post.

    Thread Starter Agence Myso

    (@agence-myso)

    Thanks for your advice!
    I’m nearly done! Hope all this will help someone else one day.
    I’ll put the whole piece of code as soon as it is finished.

    Thread Starter Agence Myso

    (@agence-myso)

    I am facing new problems… ??
    When clicking on a video link, the user gets to a “single” template. The problem in my structure is I can’t get to make the menu appear on this single template as it is on the archive template. I tried to create a single.php file, but that didn’t work.
    Any idea?

    Thread Starter Agence Myso

    (@agence-myso)

    I think I’ll have to be more specific…
    The video must appear just next to the menu, on the right. So the user has the menus AND the video player on the same page. Exactly as it is on https://www.supergrafic.com right now.

    single.php is for an individual post, but since you are working with your video custom post type, give single-video.php a try. You can get more details about post type templates in the WordPress codex.

Viewing 15 replies - 1 through 15 (of 22 total)
  • The topic ‘Three levels category menu’ is closed to new replies.