Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Inside a standard WordPress loop, call get_the_category(), keep the returned terms whose parent value is 0, and render those terms. This shows only top-level categories assigned to the current post.

Show assigned top-level categories

Use this in a classic theme template, such as a post card, archive loop, or single-post metadata area:

<?php
$categories = get_the_category();
$parent_categories = array_filter(
    $categories,
    static function ( $category ) {
        return 0 === (int) $category->parent;
    }
);

if ( ! empty( $parent_categories ) ) {
    $links = array();

    foreach ( $parent_categories as $category ) {
        $links[] = sprintf(
            '<a href="%s">%s</a>',
            esc_url( get_category_link( $category->term_id ) ),
            esc_html( $category->name )
        );
    }

    echo implode( ', ', $links );
}
?>

get_the_category() returns the categories assigned to the current post as WP_Term objects. A category with parent === 0 is a top-level category, so the filter removes assigned child categories. The URL and category name are escaped before output.

Choose what “parent category” means

WordPress category hierarchies create two different requirements that are often called “show the parent.” Decide which result you need before choosing code.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Requirement Correct approach Result
Show only top-level categories directly assigned to the post get_the_category() plus a parent === 0 filter Only assigned root terms; directly assigned child terms are omitted
Show root categories for posts assigned to children or grandchildren Retrieve assigned terms, walk each ancestor chain, then deduplicate roots The root category is shown even when the post is not assigned to that root term
List every top-level category in the site get_categories( array( 'parent' => 0 ) ) All root categories in the taxonomy, not just categories assigned to this post
Show a hierarchy path get_the_category_list() with its documented parent option A parent path, rather than only one root name

Why get_categories() is usually the wrong function in a post loop

get_categories( array( 'parent' => 0 ) ) queries the category taxonomy for top-level terms across the site. It does not automatically limit the result to categories assigned to the post currently being rendered. In a post loop, start with get_the_category() when the output must describe that post.

Show the root ancestor of a child or grandchild

The simple filter only retains terms whose immediate parent is zero. For a post assigned to Grandchild, where Grandchild belongs to Child and Child belongs to Root, the grandchild’s immediate parent is Child, not zero. Walk upward until the term has no parent, and keep each root once.

Rank #2
Sale
1,000 Books to Read Before You Die: A Life-Changing List
  • Book - 1, 000 books to read before you die: a life-changing list (1000 before you die)
  • Language: english
  • Binding: hardcover
<?php
$assigned_categories = get_the_category();
$root_categories = array();

foreach ( $assigned_categories as $category ) {
    $term = $category;

    while ( ! empty( $term->parent ) ) {
        $parent = get_term( (int) $term->parent, 'category' );

        if ( is_wp_error( $parent ) || ! $parent ) {
            break;
        }

        $term = $parent;
    }

    $root_categories[ $term->term_id ] = $term;
}

if ( ! empty( $root_categories ) ) {
    $links = array();

    foreach ( $root_categories as $category ) {
        $links[] = sprintf(
            '<a href="%s">%s</a>',
            esc_url( get_category_link( $category->term_id ) ),
            esc_html( $category->name )
        );
    }

    echo implode( ', ', $links );
}
?>

The array key is the term ID, so two assigned descendants under the same root produce one root link. The loop also stops safely if an ancestor cannot be retrieved.

Display a full category path instead

If readers need context such as News > WordPress > Themes, use WordPress’s category-list formatter rather than reducing the result to one root. get_the_category_list() supports a parents option whose documented values control whether parent terms are shown for multiple levels, a single level, or not at all.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
<?php
echo get_the_category_list( ', ', 'multiple' );
?>

This is a hierarchy-path output. It is not equivalent to displaying only the root category.

Use the code outside the loop

Inside The Loop, get_the_category() defaults to the current post. Outside it, pass the post ID explicitly:

<?php
$categories = get_the_category( $post_id );

foreach ( $categories as $category ) {
    if ( 0 === (int) $category->parent ) {
        echo esc_html( $category->name );
    }
}
?>

Use the same explicit post ID when building a reusable card, widget, query callback, or other component that may not have the expected global post context.

Apply the pattern to a custom taxonomy

get_the_category() is for WordPress’s built-in category taxonomy. For a custom taxonomy, retrieve terms with get_the_terms(), check for an empty or error result, and then apply the same parent test.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
<?php
$terms = get_the_terms( get_the_ID(), 'taxonomy_name' );

if ( ! empty( $terms ) && ! is_wp_error( $terms ) ) {
    foreach ( $terms as $term ) {
        if ( 0 === (int) $term->parent ) {
            printf(
                '<a href="%s">%s</a>',
                esc_url( get_term_link( $term ) ),
                esc_html( $term->name )
            );
        }
    }
}
?>

For root ancestors of deeper custom-taxonomy terms, use the same upward traversal but pass the custom taxonomy name to get_term().

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Troubleshoot missing or unexpected output

  • No category appears: the post may have no assigned top-level category. If it is assigned only a child term, use the ancestor-traversal version.
  • Unrelated categories appear: check that you used get_the_category(), not get_categories(), for post-specific output.
  • Child categories still appear: confirm the comparison casts the parent value and checks 0 === (int) $category->parent.
  • Custom taxonomy output is empty: replace get_the_category() with get_the_terms() and use the actual taxonomy slug.
  • Links are unsafe or malformed: escape term URLs with esc_url() and visible names with esc_html().
  • Output differs between templates: verify that the code runs inside the intended loop or that an explicit post ID is supplied.

Recommended implementation

For the usual requirement—show categories assigned to the current post, but hide assigned children—use the first snippet. Use ancestor traversal only when a descendant assignment must roll up to its root. Use get_categories() for a site-wide category list, and get_the_category_list() when the reader should see the complete hierarchy path.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.