1

I have a cpt for which I need to order Wp_Query hierarchically...

Example:

Show 1
Episode 1
Episode 2

Show 2
Episode 1
Episode 2

I thought order_by=parent would do it, but apparently not so.

  • Couple of questions: 1) Is your custom post type defined as hierarchical like pages? and 2) Are you using as custom taxonomy? – Cedon Jun 12 '17 at 14:19
  • @belinus ... thanks. CPT is hierarchical, not used as custom taxonomy. – glvr Jun 12 '17 at 14:23
2

You'll need to use something other than a single WP_Query. You could use wp_list_pages() with a custom walker to get your desired structure.

wp_list_pages in widget, sidebar, or wherever you want the list to appear:

<ul class="cpt-hierarchy"><!-- or whatever class you like -->
<?php
wp_list_pages(array(
    'post_type' => 'cpt', // replace with your cpt's slug
    'title_li' => '', // don't include a title LI
    'post_status' => 'publish', // don't include private/draft/etc.
    'sort_column' => 'post_title', // order by post title
    'walker' => new wpse_hierarchy_walker)
);
?>
</ul>

Walker in theme's functions.php:

<?php
class wpse_hierarchy_walker 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 = '';
        extract($args, EXTR_SKIP);
        $css_class = array('page_item');
        if(!empty($current_page)) {
            $_current_page = get_page( $current_page );
            $children = get_children('post_type=page&post_status=publish&post_parent='.$page->ID);
            if(count($children) != 0) {
                $css_class[] = 'hasChildren';
            }
            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, $depth, $args, $current_page ) );
        if($page->ID == $current_page) {
            $output .= $indent .'<li class="' . $css_class . '">' . $page->post_title;
        } else {
            $output .= $indent .'<li class="' . $css_class . '"><a href="' . get_permalink($page->ID) . '">' . $page->post_title .'</a>';
        }
    }
}
?>

Then using CSS you can indent the children as much as you want. li.hasChildren ul will be wrapped around the children.

  • 1
    I would say turn it into a plugin though. Anything that changes/creates content structure should not be part of the theme and since this walker is dependent on the CPT, both should be rolled into a plugin instead. – Cedon Jun 12 '17 at 14:27
  • @WebElaine... follow-up - brain-faded earlier. I was using Wp_Query so that I can show title/excerpt/thumbnail... which I can probably do by adapting your code - will look at it later when fresh. – glvr Jun 12 '17 at 15:34
  • Yes, you can add those to the walker. Definitely good to look at with maximum brainpower. :) – WebElaine Jun 12 '17 at 15:38

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.