Display subcategories in wordpress, but not in a list

Viewed 679

I need to display the subcategories of of a category on my new website.

My structure is as following:

Test1
  - Sub1_1
  - Sub1_2
Test2
  - Sub2_1
  - Sub2_2

When I am on the category page of "Test1" I need to display the sub categories ("Sub1_1" and "Sub1_2"). I found the following snippet on the web which does display the sub cat:

if (is_category()) {
        $this_category = get_category($cat);
    }
    ?>
    <?php
        if($this_category->category_parent)
            $this_category = wp_list_categories('orderby=id&show_count=0&title_li=&use_desc_for_title=1&child_of='.$this_category->category_parent."&echo=0"); 
        else
            $this_category = wp_list_categories('orderby=id&depth=1&show_count=0&title_li=&use_desc_for_title=1&child_of='.$this_category->cat_ID."&echo=0");

        if ($this_category) { ?> 
            <ul>
                <?php echo $this_category; ?>
            </ul>            
        <?php } ?>

But it does this in an unordered list with <ul> and <li>.

<ul>
   <li>Sub1_1</li>
   <li>Sub1_2</li>
</ul>

Instead of this list I need to display a div with the sub category title and the corresponding sub cat description (or even better: an excerpt of the description, but for the moment I would be happy to just get the full description). The layout has to be something like

<div class="cat-list">
    <div class="cat-subcat">
       <h2 class="cat-title">Sub1_1</h2>
       <p class="cat-text">Subcat1_1 description</p>
    </div>
    <div class="cat-subcat">
       <h2 class="cat-title">Sub1_2</h2>
       <p class="cat-text">Subcat1_2 description</p>
    </div>
</div>

How can I adjust the snippet, that it can be displayed in the way I want to show it?

4 Answers

I've done it this way now and it works, but still might be too complicated or wrong or unusual... if you see any chance to improve the code, please leave a comment as I am new to PHP and WordPress templating at all ...

<?php 
  $category_ids = get_all_category_ids(); 
  $current_category = get_category( get_query_var( 'cat' ) );
  $cat_id = $current_category->cat_ID;
        
  $args = array(
          'orderby' => 'slug',
          'parent' => $cat_id
  );
  $categories = get_categories( $args );
  foreach ( $categories as $category ) {
       echo '<div><h3 class="title">' . $category->name . '</h3><div class="text">' . $category->description . '</div><div class="ink"><a href="' . get_category_link( $category->term_id ) . '">Read more</a></div></div>';
   }
?>

For getting all nested levels, you could use child_of param.

Then you could build any structure you want with array_reduce or with similar approach

$category = get_category( get_query_var( 'cat' ) );
$cat_id   = $category->cat_ID;

$categories = get_categories(
    [
        'orderby'    => 'slug',
        'child_of'   => $cat_id,
        'hide_empty' => false,
    ]
);

$content = array_reduce(
    $categories,
    function ( $content, $category ) {
        ob_start();
        ?>
        <div class="cat-subcat">
            <h2 class="cat-title"><?php echo esc_html( $category->name ) ?></h2>
            <p class="cat-text"><?php echo esc_html( $category->description ) ?></p>
        </div>
        <?php

        return $content . ob_get_clean();
    },
    ''
);

echo sprintf( '<div class="cat-list">%1</div>', $content );

This is based on your answer, but the markup/HTML is based on what you shown in the question.

If you just want a flat display of all the category's children

Then all that you need to do is use child_of in place of parent in your $args:

$args = array(
    'orderby'  => 'slug',
    'child_of' => $cat_id, // use child_of
//  'parent'  => $cat_id,  // and not parent
);

If you want a hierarchical display

I.e. The same nested structure that you'd get when using wp_list_categories().

Then you can use recursive function calls.

// In the theme functions file or maybe somewhere in your plugin.
function my_list_cats( $parent = 0, $level = 0 ) {
    $cats = get_categories( [
        'parent' => $parent,
        // other args here
    ] );

    if ( empty( $cats ) ) {
        return false;
    }

    // Just for styling purposes..
    $classes = 'level-' . absint( $level );
    $classes .= $level ? ' cat-child' : '';

    echo '<div class="cat-list ' . $classes . '">';

    foreach ( $cats as $term ) {
        echo '<div class="cat-subcat">';

        echo '<h2 class="cat-title">' . $term->name . '</h2>';

        // Please note that wp_trim_words() will strip all HTML tags.
        if ( $description = wp_trim_words( $term->description, 28 ) ) {
            echo '<p class="cat-text">' . $description . '</p>';
        }

        my_list_cats( $term->term_id, ++$level );

        echo '</div><!-- .cat-subcat -->';
    }

    echo '</div><!-- .cat-list -->';
}

Then on a category archive, in the template, just call:

my_list_cats( get_queried_object_id() );

And in the function, I used wp_trim_words() for trimming the category description by words, but you can really use your own function for trimming by characters. :)

Sample output and styling

/* Just some basic styling */

.cat-list { padding: 0 10px }

/* Main/parent category */
.cat-list.level-0 { background: #d4edda; color: #155724 }

/* All child categories */
.cat-list.cat-child { margin-left: 1em }

/* Child/sub categories levels 1 and 2 */
.cat-list.level-1 { background: #fff3cd; color: #856404 }
.cat-list.level-2 { background: #f8d7da; color: #721c24 }
<div class="cat-list level-0">
    <div class="cat-subcat">
        <h2 class="cat-title">Foo Child</h2>
        <p class="cat-text">Foo Child description</p>

        <div class="cat-list level-1 cat-child">
            <div class="cat-subcat">
                <h2 class="cat-title">Foo Subchild</h2>
                <p class="cat-text">Foo Subchild description</p>

                <div class="cat-list level-2 cat-child">
                    <div class="cat-subcat">
                        <h2 class="cat-title">Foo Sub-subchild</h2>
                        <!-- No description -->
                    </div><!-- .cat-subcat -->
                </div><!-- .cat-list -->
            </div><!-- .cat-subcat -->

            <div class="cat-subcat">
                <h2 class="cat-title">Foo Subchild 2</h2>
                <!-- No description -->
            </div><!-- .cat-subcat -->
        </div><!-- .cat-list -->
    </div><!-- .cat-subcat -->

    <div class="cat-subcat">
        <h2 class="cat-title">Foo Child 2</h2>
        <!-- No description -->
    </div><!-- .cat-subcat -->
</div><!-- .cat-list -->

Try this:

    <?php 
          $category_ids = get_all_category_ids(); 
          $current_category = get_category( get_query_var( 'cat' ) );
          $cat_id = $current_category->cat_ID;
                
          $args = array(
                  'orderby' => 'slug',
                  'parent' => $cat_id
          );
          $categories = get_categories( $args );
          foreach ( $categories as $category ) {
               echo '<div><h3 class="title">' . $category->name . '</h3><div class="text">' . $category->description . '</div><div class="ink"><a href="' . get_category_link( $category->term_id ) . '">Read more</a></div></div>';

          $subargs = array(
                  'orderby' => 'slug',
                  'parent' => $category->term_id
          );
          $subcategories = get_categories( $subargs );

 foreach ( $subcategories as $subcategory ) {
               echo '<div><h3 class="title">' . $subcategory->name . '</h3><div class="text">' . $subcategory->description . '</div><div class="ink"><a href="' . get_category_link( $subcategory->term_id ) . '">Read more</a></div></div>';
}

           }
        ?>
Related