How to display a primary category on your post excerpts.

When I’m organizing a main blog page, I often like to make the primary category stand out so readers can quickly spot the theme or topic of each post. Meanwhile, on the single post pages, I list all the categories. Here are a couple of examples of this:

Screenshot of post excerpt showing "Street Survey" as the primary category.
“Street Survey” is the primary category.
Screenshot of post excerpt showing "Assessment" as the primary category.
“Assessment” is the primary category.

I use Yoast SEO on all of my sites, which includes a feature to set a category as the primary category. This does most of the work for me, but I still want to ensure that a primary category displays even if this is not set or if Yoast SEO is disabled.

To achieve this, I’ve created a function called get_primary_category. This function takes a WordPress post ID and returns an HTML string with a link to the primary or first category of the post. I use name spacing in my theme, but if you don’t, you’ll want to add a prefix to your function name. Here is the full function:

PHP
function get_primary_category($postid): string {

    static $yoast_active = null;
    $result = '';
    $primary_term_id = '';

    // Check Yoast SEO plugin status once and cache it
    if ($yoast_active === null) {
        $yoast_active = is_plugin_active('wordpress-seo/wp-seo.php') || is_plugin_active('wordpress-seo-premium/wp-seo-premium.php');
    }

    // Retrieve the primary category if Yoast is active
    if ($yoast_active) {
        $primary_term_id = yoast_get_primary_term_id('category', $postid);
    }

    // If no primary category from Yoast, get the first category assigned to the post
    if (empty($primary_term_id)) {
        $categories = wp_get_post_terms($postid, 'category');
        if (!is_wp_error($categories) && !empty($categories)) {
            $primary_term_id = $categories[0]->term_id;
        }
    }

    // If a category ID was found, fetch and format the category link
    if ($primary_term_id) {
        $term = get_term($primary_term_id, 'category');
        if (!is_wp_error($term)) {
            $url = get_term_link($term);
            if (!is_wp_error($url)) {
                $name = esc_html($term->name);
                $result = '<a href="' . esc_url($url) . '">' . $name . '</a>';
            }
        }
    }

    return $result;
}

Building the function

First, I create a static variable and set that to null. Additionally, I also set my other variables to an empty string.

PHP
static $yoast_active = null;
$result = '';
$primary_term_id = '';

Next, I check whether Yoast SEO or Yoast SEO Premium is active and set that result to my static variable.

PHP
if ($yoast_active === null) {
  $yoast_active = is_plugin_active('wordpress-seo/wp-seo.php') || is_plugin_active('wordpress-seo-premium/wp-seo-premium.php');
    }

By setting this to a static variable, it retains its value between function calls. Therefore, the check for plugin activation only occurs once during the lifetime of the script.

The condition if ($yoast_active === null) checks if $yoast_active has not been set yet. This check is only true the first time the function is called. However, in subsequent calls within the same request, $yoast_active will already hold a value (true or false), and this block will be skipped.

Next, I want to check if Yoast SEO is active. If it is active, we want to check if a primary category has been set. If it has been set, it will be assigned to $primary_term_id.

PHP
    if ($yoast_active) {
        $primary_term_id = yoast_get_primary_term_id('category', $postid);
    }

If no primary category is found, or if Yoast SEO isn’t active, we fall back to using the first category associated with the post. To do this, we get all the categories from the post using wp_get_post_terms(). We want to check both that this function does not return an error and that it doesn’t return an empty array. Then, we can set the $primary_term_id to the first category in the array.

PHP
    if (empty($primary_term_id)) {
        $categories = wp_get_post_terms($postid, 'category');
        if (!is_wp_error($categories) && !empty($categories)) {
            $primary_term_id = $categories[0]->term_id;
        }
    }

With the $primary_term_id, we can use it to get the category object using get_term(). Now we can get the name of the category and the url to the category archive page. Now, we construct our link and set it to the $result variable.

PHP
    if ($primary_term_id) {
        $term = get_term($primary_term_id, 'category');
        if (!is_wp_error($term)) {
            $url = get_term_link($term);
            if (!is_wp_error($url)) {
                $name = esc_html($term->name);
                $result = '<a href="' . esc_url($url) . '">' . $name . '</a>';
            }
        }
    }

Finally, we return our link with the string.

PHP
    return $result;

Reader Interactions

Leave a Reply

Your email address will not be published. Required fields are marked *