0

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');

Julian
  • 598
  • 8
  • 23

2 Answers2

1

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. :)

Sally CJ
  • 15,362
  • 2
  • 16
  • 34
  • Thank you very much for your code, but when you click on books, for example, the upper category Games also appears. I described my example differently above to make it clearer. – Julian Jan 30 '22 at 20:42
  • 1
    I actually deliberately added the upper categories (i.e. parent and other ancestors) because I thought you wanted them be added.. but anyway, I've revised my answer, so try the new code and let me know. (regarding the `show_parent`, though, that is basically just as a heading) – Sally CJ Jan 31 '22 at 09:07
  • 1
    Actually, I haven't checked or didn't really notice your most recent edit on your question.. but anyway, try the new code and see if that works? – Sally CJ Jan 31 '22 at 09:11
  • The problem persists for me.When I go to /cat1 I see the heading and cat1, cat2 listed. If I click cat1, I see cat2 as well.When I click cat2 where there are multiple entries and subcats, cat1 disappears.The parent categories may also be present and clickable, but only those that belong to the direct silo.It is generally that you only see the content of the same category from the link on a page.So you can't click from books to games. when I call up the top category page, I'm not yet in the lower silos and then I can see the others. I can also select the parent categories from the lower levels. – Julian Jan 31 '22 at 09:36
  • 1
    Thanks Sally CJ, i use your first code and set some category to noindex. Works perfect now. – Julian Feb 04 '22 at 18:08
0

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>
Julian
  • 598
  • 8
  • 23