Get taxonomy description based on variable

I’m trying to display a taxonomy description based on which taxonomy the page is set to display (set with a variable)

As it is, I’m only seeing the first description, regardless of which category variable is set.

Here’s how I’ve set it up:

I’ve built a custom post type called ‘product’ and set up a taxonomy called’product_type’.

    //Register product post type
    add_action('init', 'product_register');
    function product_register() {
        $labels = array(
            'name' => ('Products'),
            'singular_name' => ('Product'),
            'add_new' => ('Add New'),
            'add_new_item' => ('Add New Product'),
            'edit_item' => ('Edit Product'),
            'new_item' => ('New Product'),
            'view_item' => ('View Product'),
            'search_items' => ('Search'),
            'not_found' => ('Nothing found'),
            'not_found_in_trash' => ('Nothing found in Trash'),
            'parent_item_colon' => ''
            );
        $args = array(
            'labels' => $labels,
            'menu_icon' => 'dashicons-tag',
            'public' => true,
            'has_archive' => true,
            'supports' => array('title', 'revisions', 'editor','thumbnail'),
            'capability_type' => 'post',
            'rewrite' => array("slug" => "product"), // Permalinks format
            );
        register_taxonomy('product_type', array('product'), array(
            'hierarchical' => true,
            'label' => 'Product Type',
            'singular_label' => 'Type',
            'show_ui' => true,
            'show_admin_column' => true,
            'query_var' => true,
            'rewrite' => true)
        );
        register_post_type( 'product' , $args );
    }

In the wordpress back end, I’ve loaded this with a few terms and have also added in descriptions.

Admin category list with values
archive-products.php works like a landing page, but will accept information from a variable called $type to filter the content.

    if (isset($_GET['type']) || !empty($_GET['type']) ) {
        $filtered = true;
        $type = $_GET['type'];
    }

With that information, I can set up a WP_Query for items that contain that taxonomy term.

    if ($filtered == true) {
        $type = explode(' ', $_GET['type']);
        $taxonomy = array(
            array(
                'taxonomy' => 'product_type',
                'field'    => 'slug',
                'terms'    => $type
                )
            );
    $args = array(
        'post_type' => 'product',
        'posts_per_page' => -1,
        'order' => 'DEC',
        'orderby' => 'title',
        'offset' => '0',
        'tax_query' => $taxonomy
        );
    $the_query = new WP_Query($args);
    if($the_query->have_posts()):
        $terms = get_the_terms( $post->ID, 'product_type' );
    if($terms) {
        foreach( $terms as $term ) {
    echo $term->description; //always shows first term description, but should display description based on $type
    }
    }
    while($the_query->have_posts()):$the_query->the_post();
    the_title();
    the_content();
    endwhile;
    else: //nothing to show here
    endif;} else {
    // non-filtered page design
    }

The query works great but, as I mentioned earlier, it’s only pulling the first taxonomy description.

This is the part that is meant to handle that:

    $terms = get_the_terms( $post->ID, 'product_type' );
    if($terms) {
        foreach( $terms as $term ) {
    echo $term->description;
    }
    }

I had guessed that it needed to be inside the query to land on the correct description, but it doesn’t seem to make a difference.

I have also tried this:

    $term = get_term_by( $post->ID, $type, 'product_type' );
    echo $term->description;

but that doesn’t return anything.

I’m out of ideas. I haven’t found anything via google or by searching this site.

Any advice is appreciated, thanks in advance.

1 Answer
1

You have a lot of issues here:

  • You should not be using $_GET variables without sanitizing it. Never ever trust any user inputs and URL parameters. They might contain malicious code which can harm your site. To sanitize and validate a $_GET variable, use the filter_input php function

    $filtered = filter_input( INPUT_GET, 'type', FILTER_SANITIZE_STRING )
    
  • Use the main query and use pre_get_posts to filter the main query accordingly. There is no need to use a custom query as this is an archive page

  • You are trying to get the current term description wrong, you should be using get_term_by to get the term object which will hold the info you need

  • This might be unrelated, but why aren’t you using a taxonomy.php page which will handle all the above as it should. You just need to flush your permalinks and everything should work as it should. But this is something you need to look into in your own time

Lets first sort out the archive page. I have commented the code in order to make it easy to understand. I don’t know how many terms you will pass, but from your code I have taken more that 1. If not, please see the code and adjust accordingly

$filtered = filter_input( INPUT_GET, 'type', FILTER_SANITIZE_STRING );
if ( $filtered  ) {
    /**
     * I don't know if you will be passing more than one term. From your code it seems so
     */
    $types = explode( ' ', $filtered ); 
    foreach ( $types as $type ) {

        /**
         * Get the term object. 
         *
         * I have used the slug here as it seems that you are passing the slug. Adjust as necessary
         *
         * @see get_term_by()
         */
        $term = get_term_by( 'slug', $type, 'product_type' );
        // Make sure that $term has a valid value before outputting anything
        if ( !empty( $term ) || !is_wp_error( $term ) )
            echo $term->description; // Show term description
    }
    /* Replace code above with the following if you are passing just one term
    $term = get_term_by( 'slug', $filtered, 'product_type' ); 
    if ( !empty( $term ) || !is_wp_error( $term ) )
        echo $term->description; // Show term description
    */
    if ( have_posts() ) {
        while( have_posts() ) {
            the_post();

            the_title();
            the_content();
        }
    }

} else {

    // non-filtered page design
    // I don't know what will be displayed here, so I'm keeping the loop and this separate

}

This should sort the archive page. By default, the following is passed by default, so we will not pass them in our action

  • post type

  • offset.

So, lets look at our action. I have again commented the code to make it easy to follow. Please note, the following requires at least PHP 5.4+ due to the short array syntax ([]) being used. For older versions, roll back to old array syntax (array())

add_action( 'pre_get_posts', function ( $q ) 
{
    $filtered = filter_input( INPUT_GET, 'type', FILTER_SANITIZE_STRING );
    if (    !is_admin() // Only target the front end
         && $q->is_main_query() // Only target the main query
         && $q->is_post_type_archive( 'product' ) // Only target product archive page
         && $filtered // If we have a $_GET['type'] variable
    ) {
        if ( isset( $q->get( 'tax_query' ) ) ) //Get current tax query
            $tax_query = []; // Set current tax_query to an empty array

        // Set our new tax_query
        $tax_query = [
            [
                'taxonomy'         => 'product_type',
                'field'            => 'slug'
                'terms'            => explode( ' ', $filtered ),
                'include_children' => false
            ]
        ];
        $q->set( 'tax_query', $tax_query ); // Set new tax_query
        $q->set( 'posts_per_page', -1 ); // Get all posts
        $q->set( 'order', 'DESC' ); // Descending sort order
        $q->set( 'orderby', 'title' ); // Sort by title
    }
});

I hope this is what you need

Leave a Comment