1

I want to add custom classes to my menu items. For every subpage I show its siblings as a navigation:

 global $post;     

        if ( is_page() && $post->post_parent ) {


            $args = array(
                'sort_column'  => 'menu_order',
                'title_li'     => '',
                'child_of'=> $post->post_parent
            );
            $childpages = wp_list_pages($args );

        }

This gives me a list with links. I want to give every anchor element the same custom class. How do I do that?

  • Is it intended for anchor CSS styling or other purposes? – Max Yudin Mar 30 '16 at 13:18
  • Yes, it is for css styling. – Mathias Mar 30 '16 at 13:22
0

One of the ways is to extend Walker_Page class. See comment in the code to know where changes go.

class My_Siblings_CSS_Walker_Page extends Walker_Page {
    public function start_el( &$output, $page, $depth = 0, $args = array(), $current_page = 0 ) {
        if ( $depth ) {
            $indent = str_repeat( "\t", $depth );
        } else {
            $indent = '';
        }

        $css_class = array( 'page_item', 'page-item-' . $page->ID );

        if ( isset( $args['pages_with_children'][ $page->ID ] ) ) {
            $css_class[] = 'page_item_has_children';
        }

        if ( ! empty( $current_page ) ) {
            $_current_page = get_post( $current_page );
            if ( $_current_page && 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';
        }

        $css_classes = 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 );
        }

        $args['link_before'] = empty( $args['link_before'] ) ? '' : $args['link_before'];
        $args['link_after'] = empty( $args['link_after'] ) ? '' : $args['link_after'];

        $output .= $indent . sprintf(
            // '<li class="%s"><a href="%s">%s%s%s</a>', // before
            '<li class="%s"><a href="%s" class="my-custom-css-class">%s%s%s</a>', // after 
            $css_classes,
            get_permalink( $page->ID ),
            $args['link_before'],
            apply_filters( 'the_title', $page->post_title, $page->ID ),
            $args['link_after']
        );

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

            $date_format = empty( $args['date_format'] ) ? '' : $args['date_format'];
            $output .= " " . mysql2date( $date_format, $time );
        }
    }
}

Use this custom Walker in your template:

$args = array(
    'sort_column' => 'menu_order',
    'title_li'    => '',
    'child_of'    => $post->post_parent
    'walker'      => new My_Siblings_CSS_Walker_Page() // use Walker here
);
// $childpages = wp_list_pages($args);
wp_list_pages($args); // as you utilize default 'echo' parameter (true)

The way much easier is to use jQuery.

  • I would advise strongly against this, as you are basically replacing a part of WordPress core with your own functionality. Even though you're extending the Walker_Page class, you're overwriting a significant chunk of native WordPress code. This results in inconsistency if the functionality of WordPress core is changed (which happens a lot). As @Mathias needs this for CSS styling, using a WordPress native filter to alter the behaviour of the parent element is much more secure and scalable solution. – engelen Mar 30 '16 at 14:51
  • @engelen This walker is used only when it's explicitly called. It extends, not replaces. If walker parameter is undefined, all list functions use default Walkers, so none of the basic functionality was hurt. Also, this method is much more flexible and allow other magic tricks with lists. – Max Yudin Mar 30 '16 at 15:03
  • Yes, I am aware of that. I should have been more specific in my first sentence: you're replacing WordPress' native functionality for this instance, but you're still replacing it. As WordPress is not set up very modular, you're copying tens of lines of code from the current version of WordPress and altering just a single one (for adding my-custom-css-class). Now, if WordPress is updated, all other page lists are changed according to the new start_el code, but it isn't for your custom Walker. Thus, you're potentially using outdated code. – engelen Mar 30 '16 at 15:08
  • There's a filter available to change WordPress' behaviour in this case, and it should be used. It's specifically intended for this purpose, and is future-proof. In practice, extending the walker will probably not need to problems, but it's bad practice when a fitting filter is available. – engelen Mar 30 '16 at 15:09
  • @engelen +1. I looked into Walker_Page diff between v.3.9.11 and v.4.4.2 and I agree with you on "potentially using outdated code". On the other hand, I never had any problems with extended Walkers. – Max Yudin Mar 30 '16 at 15:44
3

There is no good filter to add the CSS classes to the anchor (<a>) elements, but as you need it for CSS styling you can use the filter for the <li> elements. This filter is called page_css_class, which is, natively, used solely in listing pages through wp_list_pages(). It filters the classes used for the li-tags.

To use this filter, simply hook into it:

function wpse222112_pagelist_item_css_classes( $classes ) {
    $classes[] = 'wpse222112-class';
    return $classes;
}

add_filter( 'page_css_class', 'wpse222112_pagelist_item_css_classes' );

If you need it only for this menu, be sure to remove it after calling wp_list_pages() using

remove_filter( 'page_css_class', 'wpse222112_pagelist_item_css_classes' );

For the sake of completeness: there is also a filter for the entire output of the page list, which you would need to use if it were necessary to add a class to the anchor tags (which it isn't in your case). This filter is wp_list_pages.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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