Custom Tag Cloud widget missing tags

What tags/terms/taxons do you get?

The the_tags( $before = null, $sep = ', ', $after="" ) function is a wrapper for get_the_tag_list( $before="", $sep = '', $after="", $id = 0 ).

This function applies the filter the_tags on the get_the_term_list( 0, 'post_tag', $before="", $sep = '', $after="" ) (0 is the $id and $post_tag the $taxonomy argument) for the post_tag taxonomy and returns it. And get_the_term_list() is responsible for fetching the tags and building the MarkUp.

To fetch the terms, it uses get_the_terms( $id, $taxonomy ) internally. If you look at the internals of those functions (see links), it uses the get_post() if no $id was provided.

This indicates that you always will only get the tags/terms for a single post. To illustrate that, here’re the first lines of the get_the_terms( $id, $taxonomy ) function:

function get_the_terms( $post, $taxonomy ) {
    if ( ! $post = get_post( $post ) )
        return false;

    $terms = get_object_term_cache( $post->ID, $taxonomy );
    if ( false === $terms ) {
        $terms = wp_get_object_terms( $post->ID, $taxonomy );
        wp_cache_add($post->ID, $terms, $taxonomy . '_relationships');
    }

As you can see, the second function in those wrappers provides no ID already, so it falls back to an ID of 0. And that makes if fall back to the global $post/\WP_Post object, which is the one from the main query (where \WP_Query->current_post points to). That can be a lot. At first it’s the first post in the loop of the main query, which is run per default. Then, if the query does not get reset after the loop, it’s the last post, etc. If you have later loops for e.g. done by plugins or your theme, it’s a different post and so on.

Conclusion: If you fall back to the global post object, then you are using what ever the (unreliable) global provides you with.

What I would suggest is to use get_terms() instead as its output is easier to control and it does not rely on using data from a post – which you don’t want.

Additional notes

Why not to use extract()? Because

  1. IDEs (like PHPStorm, Sublime, Aptana, etc.) do not recognize the origins/contents.
  2. It is unreliable as you never know if something is set or not. Use the normal array instead and rely on defaults and check it with empty() or isset():

    public function( Array $args )
    {
        $foo = isset( $args['foo'] )
            ? $args['foo']
            : 'my default';
        // work with `$foo`