2

Currently I'm using

<?php wp_list_pages( 'post_type=region&title_li=' ); ?>

To get the hierarchical list of my custom posts 'region'. It works perfectly. I got this :

  • Europe
    • Belgium
    • France
  • Asia
    • China

With a link on each item. BUT some pages have no content. It's just there to create the hierarchy. In this example, ASIA has no content.

So I'd like a way to create this menu list but if the page has no content -> no link for this element.

So I suppose, I need to use another way than wp_list_pages. But which one ?

Can you help me ?

Thank you !

1 Answer 1

1

wp_list_pages() uses a walker named Walker_Page to render its output and this can be overridden.

Below is a customized version of Walker_Page::start_el(). The code was first copied from the core, then a simple check was added before outputting the link. If a post does not have any content, then the title is wrapped in a <span> tag rather than an <a>.

Here, the modification is highlighted:

    ...
    // Modification: If a posts content is empty, do not link the item. Instead use a span tag to wrap the text.
    $maybe_link_item = empty( $page->post_content ) ? '<li class="%s"><span class="no-link">%3$s%4$s%5$s</span>' : '<li class="%s"><a href="%s">%s%s%s</a>';

    $output .= $indent . sprintf(
        $maybe_link_item, // Modification: Using this variable instead of '<li class="%s"><a href="%s">%s%s%s</a>'
        $css_classes,
        get_permalink( $page->ID ),
        $args['link_before'],
        /** This filter is documented in wp-includes/post-template.php */
        apply_filters( 'the_title', $page->post_title, $page->ID ),
        $args['link_after']
    );
    ...

Here is the full walker:

class WPSE_Walker_Page extends Walker_Page {
    // Copied from Walker_Page::start_el() core version v4.7.4.
    /**
     * Outputs the beginning of the current element in the tree.
     *
     * @see Walker::start_el()
     * @since 2.1.0
     * @access public
     *
     * @param string  $output       Used to append additional content. Passed by reference.
     * @param WP_Post $page         Page data object.
     * @param int     $depth        Optional. Depth of page. Used for padding. Default 0.
     * @param array   $args         Optional. Array of arguments. Default empty array.
     * @param int     $current_page Optional. Page ID. Default 0.
     */
    public function start_el( &$output, $page, $depth = 0, $args = array(), $current_page = 0 ) {
        if ( isset( $args['item_spacing'] ) && 'preserve' === $args['item_spacing'] ) {
            $t = "\t";
            $n = "\n";
        } else {
            $t = '';
            $n = '';
        }
        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';
        }

        /**
         * Filters 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_classes = implode( ' ', apply_filters( 'page_css_class', $css_class, $page, $depth, $args, $current_page ) );

        if ( '' === $page->post_title ) {
            /* translators: %d: ID of a post */
            $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'];

        // Modification: If a posts content is empty, do not link the item. Instead use a span tag to wrap the text.
        $maybe_link_item = empty( $page->post_content ) ? '<li class="%s"><span class="no-link">%3$s%4$s%5$s</span>' : '<li class="%s"><a href="%s">%s%s%s</a>';

        $output .= $indent . sprintf(
            $maybe_link_item, // Modification: Using this variable instead of '<li class="%s"><a href="%s">%s%s%s</a>'
            $css_classes,
            get_permalink( $page->ID ),
            $args['link_before'],
            /** This filter is documented in wp-includes/post-template.php */
            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 );
        }
    }
}

To use the new walker, add it to your theme's functions.php or to a plugin, then modify the call to wp_list_pages() so that it uses our new custom walker:

    wp_list_pages( [
        'post_type' => 'region',
        'walker'    => new WPSE_Walker_Page(),
        'title_li'  => '',
    ] );
2
  • 1
    Waouuw That's so nice of you ! That is an amazing answer! Clear and complete! It works perfectly ! Thank you so much !!
    – Emersion
    May 3, 2017 at 18:12
  • Thank you for the great question, @Emersion! If you feel like this has resolved your issue, please click the grey checkmark next to the answer to close it out. Welcome to WPSE! May 3, 2017 at 18: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.