1

I'm trying to 'break apart', (think explode is the correct terminology), wp_list_pages in order to add some definition list code into it, (dl, dt, dd).

Here is the html code that I'm trying to output:

<div id="nav">             
            <ul id="drop-nav">                 
                <li><a href="#">About Us</a>
                <div class="subnav">
                        <div class="subnavTop">
                            <ul class="subnavContent">
                                <li>
                                    <dl>                                             
                                        <dt><a href="#">Help Desk</a></dt>
                                        <dd><a href="#">Email your question</a></dd>
                                        <dd><a href="#">Text a question</a></dd>            
                                    </dl>                                      
                                    <dl>
                                        <dt><a href="#">Life stories</a></dt>                                                 
                                        <dt><a href="#">Statistics</a></dt>
                                        <dd><a href="#">World Statistics</a></dd>
                                        <dd><a href="#">UK Statistics</a></dd>
                                        <dd><a href="#">South West Statistics</a></dd>
                                        <dd><a href="#">Research projects</a></dd>                    
                                    </dl>                                        
                                </li>                   
                            </ul>
                        </div>                           
                    </div>
                </li> 
                <li><a href="#">Talk to us</a></li>
            </ul>
            <br style="clear: left" />
    </div>

Here is my current outputted html code:

<div id="nav">  
            <ul id="drop-nav">          
                <li><a href="#">About Us</a>
                <div class="subnav">
                        <div class="subnavTop">
                            <ul class="subnavContent">
                                <li class="page_item page-item-15"><a href="#">Child of About</a>
                                    <ul class='children'>
                                        <li class="page_item page-item-28"><a href="#">Grandchild of About</a></li>
                                    </ul>
                                </li>

                            </ul>
                        </div>
                    </div>
                </li>
                <li><a href="#">Talk to us</a></li>
            </ul>
    <br style="clear: left" />
    </div>

Which is generated using the following code from within my header.php, (can't remember which site I found this on):

<div id="nav">  
    <ul id="drop-nav">          
    <?php
    // Query the database for all top-level page IDs, and store them in the $menuPages array under the [ID] sub-array
    $menuPages = $wpdb->get_results("SELECT ID FROM $wpdb->posts WHERE post_parent=0 AND post_type='page' AND post_status='publish' ORDER BY menu_order ASC");

    // For each element in the $menuPages array, get the value from the [ID]-subarray to create the top-level menu and it's children
    foreach($menuPages as $menuItem){
        $menuItemTitle = get_the_title($menuItem->ID);          
        $menuItemClass = strtolower(trim($menuItemTitle));                  
        $menuItemClass = preg_replace('/[^a-z0-9-]/', '-', $menuItemClass);
        $menuItemClass = preg_replace('/-+/', "-", $menuItemClass);             
        $menuItemPermalink = get_permalink($menuItem->ID);
            if (isset($menuItemTitle) && $menuItemTitle != 'Home'){                 
                _e('<li class="'.$menuItemClass.'">'.PHP_EOL);
                _e('<a href="'.$menuItemPermalink.'">'.$menuItemTitle.'</a>'.PHP_EOL);

            // Run wp_list_pages to fetch any children, and put the HTML <LI> list results into $menuItemChildren as a string
                $menuItemChildren = wp_list_pages('title_li=&echo=0&depth=1&sort_column=menu_order&child_of='.$menuItem->ID);

            // If results were returned, $menuItemChildren is now a string with HTML in it, so create a drop-down and echo out the HTML
                if($menuItemChildren){                      
                    _e('<div class="subnav">'.PHP_EOL);
                    _e('<div class="subnavTop">'.PHP_EOL);
                    _e('<ul class="subnavContent">'.PHP_EOL);                                   
                    echo $menuItemChildren . PHP_EOL;
                    _e('</ul>'.PHP_EOL);
                    _e('</div>'.PHP_EOL);
                    _e('</div>'.PHP_EOL);                       
                }
                _e('</li>'.PHP_EOL);            
            }
        }
    ?>
    </ul>
    <br style="clear: left" />
    </div>

To be honest, this is confusing the life out of me. I can see that it should work, just not sure how to make it work. I somehow need to change each child page/item into a , the grandchildren into 's, all wrapped up nicely in 's.

Hope this makes sense. Any ideas/help greatly appreciated, S.

(The code is being used to dynamically generate a 'mega-menu')

/*Updated Walker Class code below 08-03-11, as originally provided by wyrfel - many thanks */

class My_Walker_Page extends Walker {
var $tree_type = 'page';

var $db_fields = array ('parent' => 'post_parent', 'id' => 'ID');

function start_lvl(&$output, $depth) {
    $indent = str_repeat("\t", $depth);
    switch ($depth) {
        case 0:
            $output .= "<div class=\"subnav\">\n";
            $output .= "<div class=\"subnavTop\">\n";
            $output .= $indent."<ul class='subnavContent'>\n";
            $output .= "<li>\n<dl>\n";
            break;
        case 1:                
            break;
        default:
            break;
    }
}

function end_lvl(&$output, $depth) {
    $indent = str_repeat("\t", $depth);
    switch ($depth) {
        case 0:
            $output .= "\n</dl>\n</li>\n";
            $output .= "</ul>\n";
            $output .= "</div>\n";
            $output .= "</div>\n";
            break;
        case 1:                
            break;
        default:
            break;
    }
}

function start_el(&$output, $page, $depth, $args, $current_page) {
    if ( $depth )
        $indent = str_repeat("\t", $depth);
    else
        $indent = '';

    extract($args, EXTR_SKIP);
    $css_class = array('page_item', 'page-item-'.$page->ID);
    if ( !empty($current_page) ) {
        $_current_page = get_page( $current_page );
        _get_post_ancestors($_current_page);
        if ( isset($_current_page->ancestors) && in_array($page->ID, (array) $_current_page->ancestors) )
            $css_class[] = 'current_page_ancestor';
        if ( $page->ID == $current_page )
            $css_class[] = 'current_page_item';
        elseif ( $_current_page && $page->ID == $_current_page->post_parent )
            $css_class[] = 'current_page_parent';
    } elseif ( $page->ID == get_option('page_for_posts') ) {
        $css_class[] = 'current_page_parent';
    }

    $css_class = implode(' ', apply_filters('page_css_class', $css_class, $page));

    $page_link = '<a href="' . get_permalink($page->ID) . '" title="' . esc_attr( wp_strip_all_tags( apply_filters( 'the_title', $page->post_title, $page->ID ) ) ) . '">' . $link_before . apply_filters( 'the_title', $page->post_title, $page->ID ) . $link_after . '</a>';
    $top_class = strtolower(trim($page->post_title));                   
    $top_class = preg_replace('/[^a-z0-9-]/', '-', $top_class);
    $top_class = preg_replace('/-+/', "-", $top_class);         

    switch ($depth) {
        case 0:
            $output .= $indent . '<li class="' . $top_class . '">'.$page_link . PHP_EOL;
            break;
        case 1:
            $output .= $indent . '<dt>'.$page_link.'</dt>' . PHP_EOL;
            break;
        default:
            $output .= $indent . '<dd>'.$page_link.'</dd>' . PHP_EOL;
            break;
    }

    if ( !empty($show_date) ) {
        if ( 'modified' == $show_date )
            $time = $page->post_modified;
        else
            $time = $page->post_date;
        $output .= " " . mysql2date($date_format, $time);
    }
}

function end_el(&$output, $page, $depth) {
    switch ($depth) {
        case 0:
            $output .= "</li>\n";
            break;
        case 1:
            break;
        default:
            break;
    }
}
}

2 Answers 2

1

This is one of those question where solid answer is not an easy one to follow. This function is powered by Walker_Page class and you can replace it with your own walker (extended from Walker_Page or just Walker) by passing its name in walker argument to wp_list_pages().

In a nutshell it is very highly flexible way to do it, but not very convenient and easy to grasp, especially when not messing with walkers regularly.

2
  • 1
    +1, Heres 2 examples though, #1 click me, #2 click me
    – t31os
    Mar 4, 2011 at 0:02
  • many thanks - not much about on the old walker class; far too complicated methinks!
    – sta777
    Mar 4, 2011 at 14:08
0

I cannot test this right now, but i tried writing your walker for you. It doesn't exactly do what you want as the top-levels class/id attributes are hard to modify, but everything below that should be fine (or so i hope).

class My_Walker_Page extends Walker {
    var $tree_type = 'page';

    var $db_fields = array ('parent' => 'post_parent', 'id' => 'ID');

    function start_lvl(&$output, $depth) {
        $indent = str_repeat("\t", $depth);
        switch ($depth) {
            case 0:
                $output .= $indent."<ul id=\"drop_nav\">\n";
                break;
            case 1:
                $output .= "<div class=\"subnav\">\n";
                $output .= "<div class=\"subnavTop\">\n";
                $output .= $indent."<ul class='subnavContent'>\n";
                $output .= "<li>\n<dl>\n";
                break;
            default:
                break;
        }
    }

    function end_lvl(&$output, $depth) {
        $indent = str_repeat("\t", $depth);
        switch ($depth) {
            case 0:
                $output .= "\n".$indent."</ul>\n";
                break;
            case 1:
                $output .= "\n</dl>\n</li>\n";
                $output .= "</ul>\n";
                $output .= "</div>\n";
                $output .= "</div>\n";
                break;
            default:
                break;
        }
    }

    function start_el(&$output, $page, $depth, $args, $current_page) {
        if ( $depth )
            $indent = str_repeat("\t", $depth);
        else
            $indent = '';

        extract($args, EXTR_SKIP);
        $css_class = array('page_item', 'page-item-'.$page->ID);
        if ( !empty($current_page) ) {
            $_current_page = get_page( $current_page );
            _get_post_ancestors($_current_page);
            if ( isset($_current_page->ancestors) && in_array($page->ID, (array) $_current_page->ancestors) )
                $css_class[] = 'current_page_ancestor';
            if ( $page->ID == $current_page )
                $css_class[] = 'current_page_item';
            elseif ( $_current_page && $page->ID == $_current_page->post_parent )
                $css_class[] = 'current_page_parent';
        } elseif ( $page->ID == get_option('page_for_posts') ) {
            $css_class[] = 'current_page_parent';
        }

        $css_class = implode(' ', apply_filters('page_css_class', $css_class, $page));

        $page_link = '<a href="' . get_permalink($page->ID) . '" title="' . esc_attr( wp_strip_all_tags( apply_filters( 'the_title', $page->post_title, $page->ID ) ) ) . '">' . $link_before . apply_filters( 'the_title', $page->post_title, $page->ID ) . $link_after . '</a>';
        switch ($depth) {
            case 0:
                $output .= $indent . '<li class="' . $css_class . '">'.$page_link;
                break;
            case 1:
                $output .= $indent . '<dt class="' . $css_class . '">'.$page_link;
                break;
            default:
                $output .= $indent . '<dd class="' . $css_class . '">'.$page_link;
                break;
        }

        if ( !empty($show_date) ) {
            if ( 'modified' == $show_date )
                $time = $page->post_modified;
            else
                $time = $page->post_date;

            $output .= " " . mysql2date($date_format, $time);
        }
    }

    function end_el(&$output, $page, $depth) {
        switch ($depth) {
            case 0:
                $output .= "</li>\n";
                break;
            case 1:
                $output .= "</dt>\n";
                break;
            default:
                $output .= "</dd>\n";
                break;
        }
    }
}

You should be able to just do:

$args = array(
    'title_li' => '',
    'sort_column' => 'menu_order',
    'walker' => new My_Walker_Page(),
);
wp_list_pages($args);
3
  • I should mention that i couldn't be bothered taking care of the indentation.
    – wyrfel
    Mar 4, 2011 at 19:16
  • Wow! Thank you so much! I can't express my appreciation enough! I had to tweak the code slightly and have posted final code with my original question. Again, many, may thanks, S.
    – sta777
    Mar 8, 2011 at 10:13
  • @ss888: Glad it hit the spot.
    – wyrfel
    Mar 8, 2011 at 10:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.