Ask your WordPress questions! Pay money and get answers fast! (more info)

Accordion Nav (Walker Nav or better solution)

  • REFUNDED

Hey fellow coders,

Currently I have this for my client a "vertical tab system" that loops through my custom post area called "My Races" , the tabs grab the Titles , and the content area loads up the data, The way I got it working was by using the_ID(); so when I click on the tab it shows the corresponding content. I've attached a screencap to help show what I'm doing.


but now my client has changed his mind again .. and was hoping to be able to have more control over the side nav, so we plan to use a accordion menu with parent/ sub items (on click will reveal sub items)

I was just wondering what is the best way to approach this so my client each week can add in his "custom posts" into the Menu on the backend of wordpress and Will it be possible to still use the_ID(); ? Would like to avoid having to refactor the entire page as it works good.

And would we use a Walker Nav or getItems (from my research not sure whats the easiest way) the main problem I currently find is having to make the link get the_ID and link to a page.


Here is my current code with the vertical tabs,


<section>

<div class="racers">
<div class="vertical-tabs-container">


<div class="vertical-tabs">
<p><?php echo date('Y'); ?> Race Results</p>
<?php if ( $the_query->have_posts() ) : while ( $the_query->have_posts() ) : $the_query->the_post(); ?>

<a href="javascript:void(0)" class="js-vertical-tab vertical-tab page-item" rel="<?php the_ID();?>">
<?php the_title(); ?>
</a>

<?php endwhile; else: ?>
<?php endif; ?>
<?php wp_reset_postdata(); ?>




</div>
<!-- Tab Buttons -->



<!-- Tab Content Area -->
<div class="vertical-tab-content-container">
<?php if ( $the_query->have_posts() ) : while ( $the_query->have_posts() ) : $the_query->the_post(); ?>


<!-- Content Txt -->
<div id="<?php the_ID();?>" class="js-vertical-tab-content vertical-tab-content">
<table class="tables">
<p>Race: <?php echo the_title(); ?></p>
<thead>
<tr>
<th class="pos">Pos</th>
<th class="date">Date</th>
<th class="station">Station</th>
<th class="birds">Birds</th>
<th class="lofts">Lofts</th>
<th class="release">Release</th>
</tr>
</thead>
<tbody>
<?php

// check if the repeater field has rows of data
if( have_rows('club_results') ): ?>

<?php while ( have_rows('club_results') ) : the_row(); ?>

<tr>
<td class="data-pos"><?php the_sub_field('position'); ?></td>
<td><?php the_sub_field('date'); ?></td>
<td><?php the_sub_field('loft_summary'); ?></td>
<td><?php the_sub_field('birds'); ?></td>
<td><?php the_sub_field('lofts'); ?></td>
<td><?php the_sub_field('release'); ?></td>
</tr>

<?php endwhile; else : endif; ?>
</tbody>
</table>
</div>

<?php endwhile; else: ?>
<?php endif; ?>
<?php wp_reset_postdata(); ?>

</div>
<!-- Tab Content Area -->


</div>

</div>
</section>


Answers (2)

2016-04-06

Rempty answers:

If you want use a custom walker to add the ID to the rel you can use this


class description_walker extends Walker_Nav_Menu
{
function start_el(&$output, $item, $depth, $args)
{
global $wp_query;
$pageid = $wp_query->post->ID;
$indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';

$class_names = $value = '';
$classes = empty( $item->classes ) ? array() : (array) $item->classes;
$class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item ) );
$class_names = ' class="'. esc_attr( $class_names ) . '"';

$output .= $indent . '<li id="menu-item-'. $item->ID . '"' . $value . $class_names .'>';
$thepostid=get_post_meta( $item->ID, '_menu_item_object_id', true );

$attributes = ! empty( $item->attr_title ) ? ' title="' . esc_attr( $item->attr_title ) .'"' : '';
$attributes .= ! empty( $item->target ) ? ' target="' . esc_attr( $item->target ) .'"' : '';
$attributes .= ! empty( $thepostid ) ? ' rel="' . esc_attr( $thepostid ) .'"' : '';
$attributes .= ! empty( $item->url ) ? ' href="' . esc_attr( $item->url ) .'"' : '';

$prepend = '<strong>';
$append = '</strong>';
$description = ! empty( $item->description ) ? '<span>'.esc_attr( $item->description ).'</span>' : '';

if($depth != 0)
{
$description = $append = $prepend = "";
}

$item_output = $args->before;
$item_output .= '<a'. $attributes . 'class="box' . $pageid . '"' .'>';
$item_output .= $args->link_before .$prepend.apply_filters( 'the_title', $item->title, $item->ID ).$append;
$item_output .= $args->link_after;
$item_output .= '</a>';
$item_output .= $args->after;

$output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
if ($item->menu_order == 1) {
$classes[] = 'first';
}
}
}


Daryl Baker comments:

How would I do this call into the template file using this nav ? (Sorry I didn't want to post to much to seem overwhelming)

This the accordion I would like to use to replace the tabs but still work with the ID's, I think it will be possible to still add in the rel="the_ID();" correct for the menu items ?

Thanks so much!



<ul class="accordion">
<li>
<a href="javascript:void(0)" class="js-accordion-trigger">Accordion Item</a>
<ul class="submenu">
<li>
<a href="javascript:void(0)">Sub Item 1</a>
</li>
<li>
<a href="javascript:void(0)">Sub Item 2</a>
</li>
</ul>
</li>

</ul>


Rempty comments:

Sorry for the delay
Using the code from http://cssmenumaker.com/blog/wordpress-accordion-menu-tutorial
Editing the nav walker to include the rel

class CSS_Menu_Maker_Walker extends Walker {

var $db_fields = array( 'parent' => 'menu_item_parent', 'id' => 'db_id' );

function start_lvl( &$output, $depth = 0, $args = array() ) {
$indent = str_repeat("\t", $depth);
$output .= "\n$indent<ul>\n";
}

function end_lvl( &$output, $depth = 0, $args = array() ) {
$indent = str_repeat("\t", $depth);
$output .= "$indent</ul>\n";
}

function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {

global $wp_query;
$indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';
$class_names = $value = '';
$classes = empty( $item->classes ) ? array() : (array) $item->classes;

/* Add active class */
if(in_array('current-menu-item', $classes)) {
$classes[] = 'active';
unset($classes['current-menu-item']);
}

/* Check for children */
$children = get_posts(array('post_type' => 'nav_menu_item', 'nopaging' => true, 'numberposts' => 1, 'meta_key' => '_menu_item_menu_item_parent', 'meta_value' => $item->ID));
if (!empty($children)) {
$classes[] = 'has-sub';
}

$class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args ) );
$class_names = $class_names ? ' class="' . esc_attr( $class_names ) . '"' : '';

$id = apply_filters( 'nav_menu_item_id', 'menu-item-'. $item->ID, $item, $args );
$id = $id ? ' id="' . esc_attr( $id ) . '"' : '';

$output .= $indent . '<li' . $id . $value . $class_names .'>';

$thepostid=get_post_meta( $item->ID, '_menu_item_object_id', true );

$attributes = ! empty( $item->attr_title ) ? ' title="' . esc_attr( $item->attr_title ) .'"' : '';
$attributes .= ! empty( $item->target ) ? ' target="' . esc_attr( $item->target ) .'"' : '';
$attributes .= ! empty( $thepostid ) ? ' rel="' . esc_attr( $thepostid ) .'"' : '';
$attributes .= ! empty( $item->url ) ? ' href="' . esc_attr( $item->url ) .'"' : '';

$item_output = $args->before;
$item_output .= '<a'. $attributes .'><span>';
$item_output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after;
$item_output .= '</span></a>';
$item_output .= $args->after;

$output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
}

function end_el( &$output, $item, $depth = 0, $args = array() ) {
$output .= "</li>\n";
}
}

I just added the $thepostid=get_post_meta( $item->ID, '_menu_item_object_id', true ); to get the postid
And replaced the rel to $attributes .= ! empty( $thepostid ) ? ' rel="' . esc_attr( $thepostid ) .'"' : '';


Daryl Baker comments:

Hey guys sorry it seemed the website was down for a bit again,

So just some small issues I cannot figured out

Currently here is the output, (after render)

<a rel="695" href="http://ne-oud.dev:8888/races/burkfalls/"><span>Burkfalls</span></a>


The problem is I need this to just change the tabs not goto a new page,

Here is the code previous for the tabs I used, (before render)

<a href="javascript:void(0)" class="js-vertical-tab vertical-tab page-item" rel="<?php the_ID();?>">


My question is, how can i get the classes in that & the href to be java.... etc , the_ID is working perfect now I tried to edit it directly in chrome dev tools but it still would not switch the tabs , is this because its dynamic and wont work that way unless its rendered out or is this just not going to work for me ? Does it have to be inside a loop to work etc like my previous tabs ?


Daryl Baker comments:

After more research it seem's like the js-vertical-tab class is what triggers it all to work the other ones are not relevant .

2016-04-06

Reigel Gallarde answers:

I can't find problem on your current code when talking about which is better...
the_ID() also is the right choice... using the_ID() will just have problem if you are using content from another post... but as much as I can think (using WordPress loop ) will still be a problem with accordion.

<blockquote>and was hoping to be able to have more control over the side nav</blockquote>
you can have more control with your current code... what seems to be the problem that the accordion can accomplish that your current code can not?

Sorry if I'm lost.

However, I can't seem to allow myself not to try to suggest better code...
You're using two loops when you could have just use one...

<section>
<?php if ( $the_query->have_posts() ) :
$tabs = $tabs_content = '';
while ( $the_query->have_posts() ) : $the_query->the_post(); ?>
<?php ob_start(); ?>
<a href="javascript:void(0)" class="js-vertical-tab vertical-tab page-item" rel="<?php the_ID();?>">
<?php the_title(); ?>
</a>
<?php $tabs .= ob_get_clean(); ?>

<?php ob_start(); ?>
<!-- Content Txt -->
<div id="<?php the_ID();?>" class="js-vertical-tab-content vertical-tab-content">
<p>Race: <?php echo the_title(); ?></p>
<table class="tables">
<thead>
<tr>
<th class="pos">Pos</th>
<th class="date">Date</th>
<th class="station">Station</th>
<th class="birds">Birds</th>
<th class="lofts">Lofts</th>
<th class="release">Release</th>
</tr>
</thead>
<tbody>
<?php
// check if the repeater field has rows of data

if( have_rows('club_results') ): ?>
<?php while ( have_rows('club_results') ) : the_row(); ?>
<tr>
<td class="data-pos"><?php the_sub_field('position'); ?></td>
<td><?php the_sub_field('date'); ?></td>
<td><?php the_sub_field('loft_summary'); ?></td>
<td><?php the_sub_field('birds'); ?></td>
<td><?php the_sub_field('lofts'); ?></td>
<td><?php the_sub_field('release'); ?></td>
</tr>
<?php endwhile; else : endif; ?>
</tbody>
</table>
</div>
<?php $tabs_content .= ob_get_clean(); ?>
<?php endwhile; else: ?>

<?php endif; ?>
<?php wp_reset_postdata(); ?>

<div class="racers">
<div class="vertical-tabs-container">
<div class="vertical-tabs">
<p><?php echo date('Y'); ?> Race Results</p>
<?php echo $tabs; ?>
</div>
<!-- Tab Buttons -->
<!-- Tab Content Area -->
<div class="vertical-tab-content-container">
<?php echo $tabs_content; ?>
</div>
<!-- Tab Content Area -->
</div>
</div>
</section>


Daryl Baker comments:

Hey thanks for offering your input I really do appreciate it, Currently the Tabs are looped, my client was hoping to be able to "build" the menu in the backend so he can have full control over it,


For example he wants this

Accordion Menu
--------------
Old Birds (Parent)
---> Child Item (Races Each Week)
---> Child Item (Races Each Week)
---------------
Young Birds (Parent)
----> Child Item (Races )

He would be able to add and remove items on the fly compared to the tabs that just auto generate all the post titles in "My Races" custom post area.

Hope this helps and thanks for the loop comment, the good part is after I do add this in I'll be back to one loop and will use your suggestions!

Thank you
D


Reigel Gallarde comments:

talking about accordion, are the parents the menu and the child the content?


Daryl Baker comments:

Let me get you a screen shot of how it should look will explain things a bit easier :)


Reigel Gallarde comments:

also, are you trying to make use of Appearance > Menus ? just confirming...


Daryl Baker comments:

Here is a screen cap, I put in the static accordion menu for now to show how I would like it to work

Hope this helps!
D