skip to Main Content

I created a sidebar for the dynamic WordPress category pages.

Example Url: https://example.com/category/firstcategory/secondcategory/othercategories/

SEO Silo:

Info about SEO Silos: What is a content silo and how does it benefit for SEO?

An imaginary company offers books, films and toys. And so the following categories are usually formed:

Company category:

* company
 ** books
 ** movies
 ** games

They have subcategories.

* company
 ** books
   *** drama
   *** comedy
 ** movies
   *** drama
   *** comedy
   *** romance
 ** games
   *** actions
   *** for kids
   *** click and point

The subcategories in turn have entries.

If I now come to the books category, only everything about books may appear in the category tree and not movies and games as well. Ideally not even the upper category, like that:

* company
 ** books
   *** drama
   ---- drama Book1
   ---- drama Book2

If I’m in the drama category for books, I dont want to see the others like comedy in the books category too.

If I’m in the Company category, its okay to see the first subcategories like:

* company
 ** books
 ** movies
 ** games

If I’m in the books category:

* company
 ** books
   *** drama
   *** comedy

Problem:

The code isn’t optimized yet, because I’m just trying out a lot.

Active Category level 2 already works (apart from the indentation).

  1. When calling up the second category, sometimes not all (existing) sub-categories appear.
  2. Probably the smallest problem is that the categories are not indented as a list.

// Manual: https://stackoverflow.com/questions/9225920/how-to-check-which-level-category-it-is-for-wordpress
function get_the_level($id, $type = 'category') {
    return count(get_ancestors($id, $type));
}

function children_sidebar_shortcode($atts) {

    global $post;

    if (!is_category()) {
        return false;
    }

    $returnval = "";
    $category = get_queried_object();
    $category_id = $category->term_id;

    $n = 0;
    $item_cat_level = 0;

    // Active Category is level 2 and more
    if (get_the_level($category_id) >= 2) {

        $returnval .= "<h2>Active Category is level 2 and more</h2>";

        $args = array(
            'type'                     => 'post',
            'child_of'                 => 0,
            'parent'                   => '',
            'orderby'                  => 'term_group', //'name',
            'order'                    => 'ASC',
            'hide_empty'               => 0,
            'hierarchical'             => 1,
            'exclude'                  => '',
            'include'                  => '',
            'number'                   => '',
            'taxonomy'                 => 'category',
            'pad_counts'               => false
        );
    } else {

        $returnval .= "<h2>Active Category is level 1 or less</h2>";

        $args = array(

            'type'                     => 'post',
            'child_of'                 => $category_id,
            'parent'                   => '', // set here same category as you want to fetch only their 1st level category  on in depth child
            'orderby'                  => 'term_group', //'name',
            'order'                    => 'ASC',
            'hide_empty'               => 0,
            'hierarchical'             => 1,
            'exclude'                  => '',
            'include'                  => '',
            'number'                   => '',
            'taxonomy'                 => 'category',
            'pad_counts'               => false
        );
    }

    $categories = get_categories($args);

    if (count($categories) > 0) {

        // show the category description
        //$returnval .= category_description();

        $returnval .= "<ul>";
        foreach ($categories as $category) {
            $item_cat_level = get_the_level($category->term_id);

            // Active Category is level 2 and more
            if (get_the_level($category_id) >= 2) {

                if (
                    // Category is part of the parent Categories/Terms
                    cat_is_ancestor_of($category->term_id, $category_id)

                    // SubLevel Category 2
                    || $item_cat_level >= 2

                    // Active Category (same)
                    || $category->term_id === $category_id
                ) {
                    $category_link = sprintf(
                        '<a href="%1$s" alt="%2$s">%3$s</a>',
                        esc_url(get_category_link($category->term_id)),
                        esc_attr($category->name),
                        esc_html($category->name)
                    );

                    $returnval .= sprintf("<li class='cat-item cat-item-%d %s'>%s", $category_id, ($category->term_id === $category_id) ? 'current-cat-ancestor' : '', $category_link);
                }
            } else {

                if (
                    // Category is part of the parent Categories/Terms
                    //cat_is_ancestor_of($category->term_id, $category_id)

                    // SubLevel Category 2
                    //|| 
                    $item_cat_level <= 1

                    // Active Category (same)
                    //|| $category->term_id === $category_id
                ) {
                    $category_link = sprintf(
                        '<a href="%1$s" alt="%2$s">%3$s</a>',
                        esc_url(get_category_link($category->term_id)),
                        esc_attr($category->name),
                        esc_html($category->name)
                    );

                    $returnval .= sprintf("<li class='cat-item cat-item-%d %s'>%s", $category_id, ($category->term_id === $category_id) ? 'current-cat-ancestor' : '', $category_link);
                }
            }
        }
        $returnval .= "</ul>";
    }

    // Attributes
    $atts = shortcode_atts(
        array(
            'name' => '',
        ),
        $atts,
        ''
    );

    return $returnval;
}
add_shortcode('children_sidebar', 'children_sidebar_shortcode');

2

Answers


  1. Chosen as BEST ANSWER

    The answer is only a temporary solution:

    I tried indenting with the query for a level change. Until then set an optical (but not semantic) indentation by a margin-left-0 to 2. With classes ml-%d (0,1,2).

    // Manual: https://stackoverflow.com/questions/9225920/how-to-check-which-level-category-it-is-for-wordpress
    function get_the_level($id, $type = 'category') {
        return count(get_ancestors($id, $type));
    }
    
    function children_sidebar_shortcode($atts) {
    
        global $post;
    
        if (!is_category()) {
            return false;
        }
    
        $returnval = "";
        $category = get_queried_object();
        $category_id = $category->term_id;
    
        $item_cat_level_last = 0;
        $item_cat_level = 0;
    
        // Active Category is level 2 and more
        if (get_the_level($category_id) >= 2) {
    
            //$returnval .= "<h2>Active Category is level 2 and more</h2>";
    
            $args = array(
                'type'                     => 'post',
                'child_of'                 => 0,
                'parent'                   => '',
                'orderby'                  => 'term_group', //'name',
                'order'                    => 'ASC',
                'hide_empty'               => 1,
                'hierarchical'             => 1,
                'exclude'                  => '',
                'include'                  => '',
                'number'                   => '',
                'taxonomy'                 => 'category',
                'pad_counts'               => false
            );
        } else {
    
            //$returnval .= "<h2>Active Category is level 1 or less</h2>";
    
            $args = array(
    
                'type'                     => 'post',
                'child_of'                 => $category_id,
                'parent'                   => '', // set here same category as you want to fetch only their 1st level category  on in depth child
                'orderby'                  => 'term_group', //'name',
                'order'                    => 'ASC',
                'hide_empty'               => 1,
                'hierarchical'             => 1,
                'exclude'                  => '',
                'include'                  => '',
                'number'                   => '',
                'taxonomy'                 => 'category',
                'pad_counts'               => false
            );
        }
    
        $categories = get_categories($args);
    
        if (count($categories) > 0) {
    
            // show the category description
            //$returnval .= category_description();
    
            $returnval .= "<ul>";
            foreach ($categories as $category) {
                $item_cat_level = get_the_level($category->term_id);
    
                // Active Category is level 2 and more
                if (get_the_level($category_id) >= 2) {
    
                    if (
                        // Category is part of the parent Categories/Terms
                        cat_is_ancestor_of($category->term_id, $category_id)
    
                        // SubLevel Category 2
                        || $item_cat_level >= 2
    
                        // Active Category (same)
                        || $category->term_id === $category_id
                    ) {
    
                        if ($item_cat_level >= 2) {
                            $category_link = sprintf(
                                '<a href="%1$s" alt="%2$s">%3$s</a>',
                                esc_url(get_category_link($category->term_id)),
                                esc_attr($category->name),
                                esc_html($category->name)
                            );
                        }else{
                            $category_link = esc_html($category->name);
                        }
    
                        $returnval .= sprintf("<li class='cat-item ml-%d cat-item-%d %s'>%s", $item_cat_level, $category_id, ($category->term_id === $category_id) ? 'current-cat-ancestor' : '', $category_link);
                    }
                } else {
    
                    if (
                        // Category is part of the parent Categories/Terms
                        //cat_is_ancestor_of($category->term_id, $category_id)
    
                        // SubLevel Category 2
                        //|| 
                        $item_cat_level <= 1
    
                        // Active Category (same)
                        //|| $category->term_id === $category_id
                    ) {
                        /*$category_link = sprintf(
                            '<a href="%1$s" alt="%2$s">%3$s</a>',
                            esc_url(get_category_link($category->term_id)),
                            esc_attr($category->name),
                            esc_html($category->name)
                        );*/
                        $category_link = esc_attr($category->name);
                        $returnval .= sprintf("<li class='cat-item ml-%d cat-item-%d %s'>%s", $item_cat_level, $category_id, ($category->term_id === $category_id) ? 'current-cat-ancestor' : '', $category_link);
                    }
                }
    
                /*if ($item_cat_level > $item_cat_level_last){
                    $item_cat_level_last = $item_cat_level;
                    $returnval .= "<ul class='children'></ul>";
                }*/
                $returnval .= "</li>";
            }
            $returnval .= "</ul>";
        }
    
        // Attributes
        $atts = shortcode_atts(
            array(
                'name' => '',
            ),
            $atts,
            ''
        );
    
        return $returnval;
    }
    add_shortcode('children_sidebar', 'children_sidebar_shortcode');
    

    I didn't link the first two category levels where the output doesn't work yet, until the code optimization. With a direct call, a 301 (permanent) redirect, which is removed again when the code is optimized.

    <IfModule mod_rewrite.c>
        RewriteEngine On
        RedirectMatch 301 ^/category/firstcategory/secondcategory/?$ https://example.com/firstcategory/secondcategory-page/
    </IfModule>
    

  2. So looking at the edited question, I think what you are really looking for is, a category tree having only the (immediate) children or siblings of the current category (i.e. the queried object/term on a category archive page), right?

    If so, then this should work for you:

    function children_sidebar_shortcode( $atts ) {
        // Do nothing if we're not on a category archive.
        if ( ! is_category() ) {
            return '';
        }
    
        // Parse the shortcode's parameters.
        $atts = shortcode_atts( array(
            'show_parent'  => 1,
        ), $atts );
    
        // Get the queried category object and ID.
        $current_cat    = get_queried_object();
        $current_cat_id = $current_cat->term_id;
    
        // Get the category's immediate children, if any.
        $parent_cat_id  = $current_cat_id;
        $categories     = get_categories( array(
            'parent'     => $parent_cat_id,
            'hide_empty' => 1,
        ) );
    
        // If none, get its siblings.
        // .. which means it's the last level.
        if ( empty( $categories ) ) {
            $parent_cat_id = $current_cat->parent;
            $categories    = get_categories( array(
                'parent'     => $parent_cat_id,
                'hide_empty' => 1,
            ) );
        }
    
        $heading = '';
        $list    = '<ul class="cat-list">';
    
        foreach ( $categories as $term ) {
            $class = 'cat-item';
    
            // If it's the current category, show the name only.
            if ( $current_cat_id === $term->term_id ) {
                $class .= ' current-cat';
    
                $cat_name = '<span>' . esc_html( $term->name ) . '</span>';
            // If it's not the current category, add a link to view the category
            // archive.
            } else {
                $cat_name = '<a href="' . esc_url( get_category_link( $term ) ) . '">' .
                    esc_html( $term->name ) . '</a>';
            }
    
            $list .= "<li class='$class'>$cat_name</li>";
        }
    
        $list .= '</ul>';
    
        if ( $parent_cat_id && $atts['show_parent'] ) {
            $term = get_category( $parent_cat_id );
    
            $heading = '<h3>' . esc_html( $term->name ) . '</h3>';
        }
    
        return "$heading $list";
    }
    

    Note regarding the shortcode parameters: I added show_parent, which if true or 1, then the immediate parent category will always be added to the output. So for example, on the Books category page, the shortcode would output something like this: (the "Books" is not a link)

    Books
    ● Comedy
    ● Drama
    

    And BTW, using a custom function to manually generate the categories list (i.e. the <li> tags) will give you full control over the HTML markup, but just so that you know, you could also use wp_list_categories() like so:

    • Just replace the entire foreach above with this:

      $list .= wp_list_categories( array(
          'current_category' => $current_cat_id,
          'parent'           => $parent_cat_id,
          'hide_empty'       => 1,
          'title_li'         => '',
          'echo'             => 0,
      ) );
      

    Last but not least, you can style the current category/<li> using the current-cat class. 🙂

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search