Search code examples
phpwordpresstaxonomy

Returning the most popular tags using meta data in wordpress


I am in the process of building a sophisticated tag cloud.

Wordpress currently has a built-in function called 'get_tags' which I am using to build a list of the most poplar tags that are used on my website.

Heres my current working php function:

function top_brand_tags($related_publication) {

        $tag_data = '';
        $tags = get_tags();

        $counts = $tag_links = array();

        foreach ( (array) $tags as $tag ) 
        {
            $counts[$tag->name] = $tag->count;
            $tag_links[$tag->name] = get_tag_link( $tag->term_id );
        }

        asort($counts);
        $counts = array_reverse( $counts, true );
        $i = 0;
        foreach ( $counts as $tag => $count ) 
        {
                $i++;
                $tag_link =  str_replace(' ', '-', wp_specialchars( $tag ));
                $tag = str_replace(' ', ' ', wp_specialchars( $tag ));

                if($i < 11)
                {
                        if ($_GET['the_post_tag'] == $tag_link){$post_tag_class = "on";}else{$post_tag_class = "";}

                        $tag_data.= '<a href="'.site_url().'/see-all?the_post_tag='.$tag_link.'&related_publication='.$related_publication.'" >
                        <li class="filter-btn">'.ucfirst($tag).' ('.$count.')</li>
                        </a>';                      
                }
        }

        return $tag_data;
}

I now need to modify this function so that it allows me to pass in a meta key and value. The function then has to search all the posts that have this key and value associated with it and return the most popular tags based on this new criteria.

So to summarise: I need to write a new function that will:

1 - Search all posts that contain a specific meta key and value

2 - Return the top 10 most used tags based on these results.


Solution

  • First, get the posts that have the wanted meta set and order by said meta.

    $posts = new WP_Query( array(
        'meta_key' => 'your_meta_key',
        'orderby' => 'meta_value' // or 'meta_value_num'
        'order' => 'DESC',
        'posts_per_page' => 50 // Grabs 50 posts at maximum, which in turn gets the tags only for those posts, set to -1 to get all posts
    ));
    

    Then go through each post and grab the tags available.

    // Save each unique tag and their count in this temp array.
    $tags_counts = array();
    
    if ( $posts -> have_posts() ) : while ( $posts -> have_posts() ) : $posts -> the_post();
    
        $post_tags = wp_get_object_terms( get_the_ID(), 'post_tag' );
    
        if ( empty( $post_tags ) {
            continue; // Skip post if no tags set.
        }
    
        foreach ( $post_tags as $tag ) {
            if ( array_key_exists( $tag -> slug, $tags_counts ) {
                // Increment tag count if tag already present.
                $tags_counts[ $tag -> slug ] = $tags_counts[ $tag -> slug ] + 1;
            }
    
            else {
                // New tag found, add to the counts list.
                $tags_counts[ $tag -> slug ] = 1;
            }
        }
    
    endwhile; endif;
    
    // Order the tag count array from most to least. Remember to reverse the sort afterwards to get "biggest first".
    asort( $tags_counts, SORT_NUMERIC ); // Use 'asort' to keep index association.
    $tags_counts = array_reverse( $tags_counts, true ); // 'true' preserves keys
    
    // If you want to limit the tags to 10 max, slice the array. Last parameter 'true' sets to preserve keys during slice operation.
    $tags_counts = array_slice( $tags_counts, 0, 10, true );
    

    Now we've gone through the posts that have the wanted meta_key set and counted the tag counts based on each. You could build a tag cloud for each as such:

    $tag_cloud = '<ul class="custom-tag-cloud">';
    
    foreach ( $tags_counts as $tag => $count ) { 
        $tag_obj = get_term_by( 'slug', $tag, 'post_tag' ); // get tag term object.
    
        // Linked element: 'tagname (count)'.
        $tag_cloud .= sprintf( '<li><a href="%s">%s (%s)</a></li>', get_tag_link( $tag_obj -> term_id ), $tag_obj -> name, $count );
    }
    
    $tag_cloud .= '</ul>';
    

    Disclaimer: not tested, but the logic should be similar to above.