0

I would like show a list of tags assigned to the current post, but exclude one by tag id.

I tried excluding it from the array of objects returned from wp_get_post_tags, something like this:

$tags = wp_get_post_tags($post->ID, array(
       'exclude' => 13
    )
);

But it doesn't looks like the wp_get_post_tags function supports exclude.

Am I wrong, or is there a better function to use in this case?

  • 1
    when you output the tags, check each one and don't output it if it's the tag you want to exclude. there is no function that has an exclude parameter for fetching terms assigned to an object. – Milo Jun 20 '16 at 2:36
1

METHOD 1 - wp_get_post_terms()

We can make use of the wpse_exclude parameter to exclude and array of terms from the list of post terms. wp_get_post_tags() internally uses wp_get_post_terms() which uses wp_get_object_terms(). When looking at the source of the latter, we see that we can make use of the wp_get_object_terms filter to filter the output from the function.

With this in mind, we can run the following filter on the output when we pass an array of id's to wpse_exclude: (NOTE: Untested and requires PHP 5.4+)

add_filter( 'wp_get_object_terms', function ( $terms, $object_ids, $taxonomies, $args )
{
    // Lets first make sure that we have terms, and only target the post_tag taxonomy
    if (    !$terms
         || is_wp_error( $terms )
    ) 
        return $terms;

    if ( 'post_tag' !== $taxonomies )
        return $terms;

    // Now we can check if our custom argument is passed and valid
    if ( !isset( $args['wpse_exclude'] ) )
        return $terms;

    // Make sure that filds are not set to names
    if ( 'names' === $args['fields'] )
        return $terms;

    // Lets validate sanitize the array of integers, might be bit verbose though
    $excluded_id_array = filter_var(  
        $args['wpse_exclude'], 
        FILTER_VALIDATE_INT,
        [
            'flags'   => FILTER_REQUIRE_ARRAY,
            'options' => ['min_range' => 1]
        ]
    );

    if ( !$excluded_id_array )
        return $terms;

    // Everything checks out, lets exclude the terms
    $new_array = [];
    foreach ( $terms as $term ) {
        if ( in_array( $term->term_id, $excluded_id_array ) )
            continue; // Skip the excluded term

        $new_array[] = $term;
    }

    // We can now return out terms
    return $new_array;
}, 11, 4 );

USAGE

$args = [
    'wpse_exclude' => [1,2,4] // Array of tag ids to eclude
];
$tags = wp_get_post_tags( get_the_ID(), $args );

IMPORTANT NOTE ON ABOVE METHOD

The method above is quite verbose. wp_get_object_terms() (which is used internally by wp_get_post_tags()) will result in an extra db call per post. Depending on the amount of posts being returned, this method can end updoing quite a number of unnecessary db calls. It is up to you to except this extra db call per post depending on what you need to do

METHOD 2

A faster and less intrusive method would be to write a simple wrapper function for get_the_tags(). get_the_tags() uses get_the_terms() which uses all term info from the term cache. By default, any query will cache all post terms for the posts queried, so any function that uses get_the_terms() will not do any extra db call to get post term info.

IMHO, I would prefer this method above the other method as it is less verbose

function wpse_230208_get_the_tags( $post_id = 0, $exclude = [] )
{
    $post_id = filter_var( $post_id, FILTER_VALIDATE_INT );
    if ( !$post_id )
        return false;

    // Get the post tags
    $tags = get_the_tags( $post_id );

    // If there are no tags, lets bail early
    if ( !$tags )
        return false;

    // Check if we have a value for $exclude, if not, return get_the_tags
    if ( !$exclude )
        return $tags;

    // Validate the array of excluded ids
    $excluded_id_array = filter_var(  
        $exclude, 
        FILTER_VALIDATE_INT,
        [
            'flags'   => FILTER_REQUIRE_ARRAY,
            'options' => ['min_range' => 1]
        ]
    );

    if ( !$excluded_id_array )
        return $tags;

    // Lets exclude the tags
    $new_tag_array = [];
    foreach ( $tags as $tag ) {
        if ( in_array( $tag->term_id, $excluded_id_array ) )
           continue; // Skip the excluded tag

        $new_tag_array[] = $tag;
    }

    return $new_tag_array
}

USAGE

$tags = wpse_230208_get_the_tags( get_the_ID(), [1,2,4] ); // Note the array of id's to be excluded as 2nd args
  • 1
    I like how you validated the input via filter_var with options. ps: I vaguely remembered the wp_is_numeric_array() function, so I checked it out again but it's not suitable since it's only meant for the array keys and returns true if is_string() is false for all keys ;-) – birgire Jun 20 '16 at 17:00
  • 1
    @birgire I tend to like the PHP filters ;-) – Pieter Goosen Jun 20 '16 at 17:08
1

Here's an approach similar to what @Milo suggests.

Let's say we have:

$tags = wp_get_post_tags( 123 );

If we need to filter out the term with term_id 15, we can use wp_list_filter:

$_tags = wp_list_filter( $tags, [ 'term_id' => 15 ], 'NOT' );

where the NOT is the operator for excluding it.

If we also need to pluck out a single attribute we can use wp_filter_object_list:

$_tags = wp_filter_object_list( $tags, [ term_id => 15 ], 'NOT', 'slug' );

where we pluck out e.g. the slug attribute.

You should also check out the informative answer by @PieterGoosen, e.g. about the flexible custom wpse_exclude attribute and the extra db call in wp_get_post_tags().

  • Jip, learned something new here. Will dig into that function a bit ;-) – Pieter Goosen Jun 20 '16 at 10:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.