Hi,
I am looking at setting up a shortcode within WordPress that will allow me to display the sub pages of a certain section.
I have mostly set this up as the menu is being displayed, but unfortunately isn't being displayed in the correct area. Please see below the code used for the shortcode:
function testing_subnav( $atts, $content = null ) {
global $post;
if ( is_page( '48' ) || '48' == $post->post_parent || (in_array("48", $post->ancestors)) ) {
$menu_args = array('menu' => 'Advertising Navigation', 'container' => '', 'walker' => new sub_nav_walker(),);
$return_string .= '<div id="inner_sub_nav">';
$return_string .= wp_nav_menu($menu_args);
$return_string .= '</div><!--inner_sub_nav-->';
}
return $return_string;
}
add_shortcode('subnav', 'testing_subnav');
As you can see, it is calling the "sub_nav_walker" function that has been coded into the functions file, below:
class sub_nav_walker extends Walker_Nav_Menu {
var $found_parents = array();
function start_el(&$output, $item, $depth, $args) {
global $wp_query;
$parent_item_id = 0;
$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).'"';
if (strpos($class_names, 'current-menu-item') || strpos($class_names, 'current-menu-parent') || strpos($class_names, 'current-menu-ancestor') || (is_array($this->found_parents) && in_array($item->menu_item_parent, $this->found_parents))) {
$this->found_parents[] = $item->ID;
if ($item->menu_item_parent != $parent_item_id) {
$output .= $indent.'<li'.$class_names.'>';
$attributes = !empty($item->attr_title) ? ' title="'.esc_attr($item->attr_title).'"' : '';
$attributes .= !empty($item->target) ? ' target="'.esc_attr($item->target).'"' : '';
$attributes .= !empty($item->xfn) ? ' rel="'.esc_attr($item->xfn).'"' : '';
$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) {
$parent_item_id = 0;
$class_names = '';
$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).'"';
if (strpos($class_names, 'current-menu-item') || strpos($class_names, 'current-menu-parent') || strpos($class_names, 'current-menu-ancestor') || (is_array($this->found_parents) && in_array($item->menu_item_parent, $this->found_parents))) {
if (is_array($this->found_parents) && in_array($item->ID, $this->found_parents) && $item->menu_item_parent != $parent_item_id) {
$output .= "</li>\n";
}
}
}
function end_lvl(&$output, $depth) {
$indent = str_repeat("\t", $depth);
if (substr($output, -22) == "<ul class=\"sub-menu\">sdf\n") {
$output = substr($output, 0, strlen($output) - 23);
} else {
$output .= "$indent</ul>\n";
}
}
}
function is_tree($pid) { // $pid = The ID of the page we're looking for pages underneath
global $post; // load details about this page
if(is_page()&&($post->post_parent==$pid||is_page($pid)))
return true; // we're at the page or at a sub page
else
return false; // we're elsewhere
};
As I said, it is pulling out the sub pages correctly, however it is displayed the sub pages above the content area and not where the shortcode has been placed, however the start and end div are appearing in the correct area.
Does anyone know how I can fix this? I have tried numerous sub pages scripts, but this is by far the best I have come across, so if we could stick with this that would be great.
Let me know.
Dbranes answers:
I think you need the <strong>"echo"=>0</strong> parameter in the<strong> $menu_args;</strong>
Dbranes comments:
So you need to have
$menu_args = array('echo' => 0, 'menu' => 'Advertising Navigation', 'container' => '', 'walker' => new sub_nav_walker(),);
otherwise <strong>wp_nav_menu()</strong> will just echo the output instead of returning it.
That could explain why you have it in a wrong place on your site.
You can check out the Codex for more info about <strong>wp_nav_menu()</strong>:
[[LINK href="http://codex.wordpress.org/Function_Reference/wp_nav_menu"]]http://codex.wordpress.org/Function_Reference/wp_nav_menu[[/LINK]]
craigfarrall comments:
Thanks for both of your help, but Dbranes, that was exactly what I was looking for, so thanks for that.
Dbranes comments:
ok great, good luck with your project ;-)
Kyle answers:
Similar questions have been posted on here before: [[LINK href="http://www.wpquestions.com/question/showChronoLoggedIn/id/8145"]]http://www.wpquestions.com/question/showChronoLoggedIn/id/8145[[/LINK]]
You can solve the question using an output buffer:
function testing_subnav( $atts, $content = null ) {
$ob_start();
global $post;
if ( is_page( '48' ) || '48' == $post->post_parent || (in_array("48", $post->ancestors)) ) {
$menu_args = array('menu' => 'Advertising Navigation', 'container' => '', 'walker' => new sub_nav_walker(),);
$return_string .= '<div id="inner_sub_nav">';
$return_string .= wp_nav_menu($menu_args);
$return_string .= '</div><!--inner_sub_nav-->';
}
return $return_string;
$output_string = ob_get_contents();
ob_end_clean();
return $output_string;
}
add_shortcode('subnav', 'testing_subnav');