0

I'm working with a tag plugin. Is there a WordPress way to get_posts or query all posts that have no tags?

EDIT

I had already queried the WP Codex, search Stackexchange and Google for a related question at the time of the question.

I found several results for helping finding tags, but not the NOT IN operator in a tax_query. I didn't have any code to share yet as I didn't have the information I needed to build the query $args.

6

A WP_Query where 'tax_query' has all tag terms and operator 'NOT IN':

$tags = get_terms('post_tag', array('fields'=>'ids') );
$args = array(
  'post_type' => 'post',
  'posts_per_page' => -1,
  'tax_query' => array(
    array(
      'taxonomy' => 'post_tag',
      'field' => 'id',
      'terms' => $tags,
      'operator' => 'NOT IN'
    )
  )
);
$untagged = new WP_Query( $args );
  • I found that the acknowledged solution only works if the post is tagged with at least one tag (in a different taxonomy, obviously). If it is not, it doesn't seem to appear in the query results. – user70493 Apr 10 '15 at 21:43
  • To invert that, which was what I was looking for, to exclude all untagged posts the tax_query simply needs terms to have an empty string passed to it and the operator set to IN like so: array('taxonomy' => 'post_tag', 'field' => 'id', 'terms' => ' ', 'operator' => 'IN'). – leymannx Apr 2 at 20:11
1

Not exactly answers the question, but might be a better solution than the above when dealing with bigger databases

// Get all posts IDs - Query took 0.0030 seconds
$all_posts_ids_query = $wpdb->prepare( "SELECT $wpdb->posts.ID FROM $wpdb->posts WHERE $wpdb->posts.post_type = '%s' GROUP BY $wpdb->posts.ID", 'your-post-type' );

$all_posts_ids = $wpdb->get_col( $all_posts_ids_query );


// Get all posts IDs that has tags - Query took 0.0300 seconds
$all_posts_ids_with_tags_query = $wpdb->prepare( "SELECT $wpdb->posts.ID FROM $wpdb->posts
    INNER JOIN $wpdb->term_relationships ON ($wpdb->posts.ID = $wpdb->term_relationships.object_id)
    INNER JOIN $wpdb->term_taxonomy ON ($wpdb->term_relationships.term_taxonomy_id = $wpdb->term_taxonomy.term_taxonomy_id)
    WHERE 1=1 AND ( $wpdb->term_taxonomy.taxonomy = '%s' )
    AND $wpdb->posts.post_type = '%s' GROUP BY $wpdb->posts.ID", 'your-taxonomy-name', 'your-post-type' );

$all_posts_ids_with_tags = $wpdb->get_col( $all_posts_ids_with_tags_query );


// Diff IDs arrays to get posts without tags
$all_posts_ids_without_tags = array_diff( $all_posts_ids, $all_posts_ids_with_tags );

DB size this was tested on (quite small but may give some representation), posts: ~3.000, terms: ~1.000, term relationships: ~6.000

0
<?php
  $args = array(
    'post_type' => 'post',
    'posts_per_page' => -1,
    'tax_query' => array(
        array(
            'taxonomy' => 'post_tag',
            'field' => 'id',
            'terms' => 'null',
            'operator' => 'NOT IN'
    )));
  $untagged = new WP_Query( $args );?>
  • This may be the right answer (I haven't checked) But you need to add explanation as well. – rudtek Apr 4 at 16:15

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.