categories and tags archive page

// create category and tags page - add a page called Categories for output


add_filter( 'template_include', 'to_category_page_template' );

function to_category_page_template( $template ) {
    if ( ! is_page( array( 'categories', 'category' ) ) ) return $template;

    add_filter( 'the_content', 'to_render_category_list' );

    return $template;
}

function to_render_category_list( $content ) {
    $categories = get_categories( array(
        'orderby'    => 'name',
        'order'      => 'ASC',
        'hide_empty' => false,
        'number'     => 0, // get all, no limit
    ) );

    if ( empty( $categories ) ) return $content;

    // Index by term_id for easy lookup
    $indexed = array();
    foreach ( $categories as $cat ) {
        $indexed[ $cat->term_id ] = $cat;
    }

    // Build tree
    $tree = array();
    foreach ( $categories as $cat ) {
        $tree[ $cat->parent ][] = $cat;
    }

    $output = '<ul>' . to_render_category_branch( $tree, 0 ) . '</ul>';

    // Tags
    $tags = get_terms( array(
        'taxonomy'   => 'post_tag',
        'orderby'    => 'name',
        'order'      => 'ASC',
        'hide_empty' => false,
        'number'     => 0,
    ) );

    if ( ! empty( $tags ) && ! is_wp_error( $tags ) ) {
        $output .= '<h2>Tags</h2><ul>';
        foreach ( $tags as $tag ) {
            $output .= '<li><a href="' . esc_url( get_tag_link( $tag->term_id ) ) . '">' . esc_html( $tag->name ) . '</a>';
            if ( ! empty( $tag->description ) ) {
                $output .= ' — ' . esc_html( $tag->description );
            }
            $output .= '</li>';
        }
        $output .= '</ul>';
    }

    return $content . $output;
}

function to_render_category_branch( $tree, $parent_id ) {
    if ( empty( $tree[ $parent_id ] ) ) return '';

    $output = '';
    foreach ( $tree[ $parent_id ] as $category ) {
        $output .= '<li>';
        $output .= '<a href="' . esc_url( get_category_link( $category->term_id ) ) . '">' . esc_html( $category->name ) . '</a>';
        if ( ! empty( $category->description ) ) {
            $output .= ' — ' . esc_html( $category->description );
        }
        if ( ! empty( $tree[ $category->term_id ] ) ) {
            $output .= '<ul>' . to_render_category_branch( $tree, $category->term_id ) . '</ul>';
        }
        $output .= '</li>';
    }

    return $output;
}

create page ‘categories’ for it to display on.