WordPress – How to change class name in wp_list_page nav

I’m using WordPress’s wp_list_pages to display a nav of pages on the site.

Some pages have children so I need a dropdown menu below those links.

Read More

The html is something like this

<ul class="">
    <li class="page_item page-item-6 current_page_item"><a href="/">Home</a></li>
    <li class="page_item page-item-6 current_page_item"><a href="/">Profile</a></li>
    <li class="page_item page-item-8 page_item_has_children dropdown">
        <a href="">Products & Services</a>
        <ul class='children'>
            <li class="page_item page-item-17"><a href="">Buying</a></li>
            <li class="page_item page-item-19"><a href="">Selling</a></li>
            <li class="page_item page-item-23"><a href="">Managing</a></li>
        </ul>
    </li>
</ul>

I wanted to use bootstrap to create the nav and dropdown menus.

Something like – http://www.ttmt.org.uk/nav/

The html for this is something like this.

<ul class="nav navbar-nav">
    <li><a href="#">Home</a></li>
    <li><a href="#">Profile</a></li>
    <li class="dropdown">
        <a href="#" data-toggle="dropdown" class="dropdown-toggle">Messages <b class="caret"></b></a>
        <ul class="dropdown-menu">
            <li><a href="#">Inbox</a></li>
            <li><a href="#">Drafts</a></li>
            <li><a href="#">Sent Items</a></li>
        </ul>
    </li>
</ul>

I need to add a ‘dropdown’ class the li and ul containing the child pages. I also need to add a class and a data-toggle attribute to the ‘a’ tag.

How can I add these clases when I using wp_list_pages and the nav is created dynamically.

I’m using this function to add ‘dropdown’ to li containin the child pages

function add_parent_class( $css_class, $page, $depth, $args ){
    if ( ! empty( $args['has_children'] ) )
        $css_class[] = 'dropdown';
    return $css_class;
}
add_filter( 'page_css_class', 'add_parent_class', 10, 4 );              

How could I extened this function add the other classes I need

Related posts

Leave a Reply

1 comment

  1. To achieve this functionality, we can not use filters only. We will have to extend the Walker class of WordPress.

    I am assuming that you have called wp_list_pages like this:

    $args = array('authors' => '',
        'child_of' => 0,
        'date_format' => get_option( 'date_format' ),
        'depth' => 0,
        'echo' => 1,
        'exclude' => '',
        'include' => '',
        'link_after' => '',
        'link_before' => '',
        'post_type' => 'page',
        'post_status' => 'publish',
        'show_date' => '',
        'sort_column' => 'menu_order, post_title',
        'sort_order' => '',
        'title_li' => __( '' ),
        'walker' => '',
    );
    
    echo '<ul class="nav navbar-nav">' . wp_list_pages( $args ) . '</ul>' ;
    

    We will pass value to walker paramter. That paramter would be object of a class that we will create now. Add this class in functions.php of your theme or in site specific plugin

    class Wdm_Walker_Page extends Walker_Page {
    
    /**
     * @see Walker::start_lvl()
     * @since 2.1.0
     *
     * @param string $output Passed by reference. Used to append additional content.
     * @param int $depth Depth of page. Used for padding.
     * @param array $args
     */
    function start_lvl( &$output, $depth = 0, $args = array() ) {
        $indent = str_repeat("t", $depth);
        $output .= "n$indent<ul class='dropdown-menu children'>n";
    }
    
    /**
     * @see Walker::start_el()
     * @since 2.1.0
     *
     * @param string $output Passed by reference. Used to append additional content.
     * @param object $page Page data object.
     * @param int $depth Depth of page. Used for padding.
     * @param int $current_page Page ID.
     * @param array $args
     */
    function start_el( &$output, $page, $depth = 0, $args = array(), $current_page = 0 ) {
        if ( $depth )
            $indent = str_repeat("t", $depth);
        else
            $indent = '';
    
        extract($args, EXTR_SKIP);
        $css_class = array('page_item', 'page-item-'.$page->ID);
    
        if( isset( $args['pages_with_children'][ $page->ID ] ) )
            $css_class[] = 'page_item_has_children dropdown';
    
        if ( !empty($current_page) ) {
            $_current_page = get_post( $current_page );
            if ( in_array( $page->ID, $_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';
        }
    
        /**
         * Filter the list of CSS classes to include with each page item in the list.
         *
         * @since 2.8.0
         *
         * @see wp_list_pages()
         *
         * @param array   $css_class    An array of CSS classes to be applied
         *                             to each list item.
         * @param WP_Post $page         Page data object.
         * @param int     $depth        Depth of page, used for padding.
         * @param array   $args         An array of arguments.
         * @param int     $current_page ID of the current page.
         */
        $css_class = implode( ' ', apply_filters( 'page_css_class', $css_class, $page, $depth, $args, $current_page ) );
    
        if ( '' === $page->post_title )
            $page->post_title = sprintf( __( '#%d (no title)' ), $page->ID );
    
        /** This filter is documented in wp-includes/post-template.php */
                if(preg_match('/dropdown/', $css_class) != FALSE){
        $output .= $indent . '<li class="' . $css_class . '"><a data-toggle="dropdown" class="dropdown-toggle" href="' . get_permalink($page->ID) . '">' . $link_before . apply_filters( 'the_title', $page->post_title, $page->ID ) . $link_after . '</a>';
                }
                else{
                    $output .= $indent . '<li class="' . $css_class . '"><a href="' . get_permalink($page->ID) . '">' . $link_before . apply_filters( 'the_title', $page->post_title, $page->ID ) . $link_after . '</a>';
                }
    
        if ( !empty($show_date) ) {
            if ( 'modified' == $show_date )
                $time = $page->post_modified;
            else
                $time = $page->post_date;
    
            $output .= " " . mysql2date($date_format, $time);
        }
        }
    }
    

    Above class adds all the classes you wanted.

    Now, we need to pass the object of this class to wp_list_pages. So it would look something like this

    $args = array(
                        'authors' => '',
                        'child_of' => 0,
                        'date_format' => get_option( 'date_format' ),
                        'depth' => 0,
                        'echo' => 1,
                        'exclude' => '',
                        'include' => '',
                        'link_after' => '',
                        'link_before' => '',
                        'post_type' => 'page',
                        'post_status' => 'publish',
                        'show_date' => '',
                        'sort_column' => 'menu_order, post_title',
                        'sort_order' => '',
                        'title_li' => __( '' ),
                        'walker' => new Wdm_Walker_Page()
                    );
    
    echo '<ul class="nav navbar-nav">' . wp_list_pages( $args ) . '</ul>' ;
    

    I Hope it helps! You don’t need to write code on filter page_css_class anymore. 🙂