Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

I feel like this should be a simple question, but I can't figure it out.

If I have a post_id, how can I remove a particular tag from that post in php?? I know how to update meta information, but tag information is different.

share|improve this question
    
Did you mean remove a tag's association with a post? As in, it was tagged 'music' or 'art' and you want to un-tag it? –  miahelf Apr 17 '12 at 5:52
    
Yes. That is what I mean. –  Alexander Bird Apr 17 '12 at 6:19

2 Answers 2

For whatever reason, Alexander Bird's routine didn't quite work for me. I modified it a little to use wp_set_post_tags instead of wp_set_object_terms:

function untag_post($post_ids, $tags) {
    global $wpdb;
    if(! is_array($post_ids) ) {
        $post_ids = array($post_ids);
    }
    if(! is_array($tags) ) {
        $tags = array($tags);
    }

    foreach($post_ids as $post_id) {
        $curtags = wp_get_post_tags($post_id, 'post_tag');
        $newtags = array();
        foreach($tags as $tag) {
            foreach($curtags as $id=>$curtag) {
                if ( $curtag->name == $tag ) {
                    unset($curtags[$id]);
                }
            }
        }

        foreach ($curtags as $curtag) {
            $newtags[] = $curtag->name;
        }

        wp_set_post_tags( $post_id, $newtags, false );
    }
}
share|improve this answer
up vote 4 down vote accepted

Below is code that works:

function untag_posts($post_ids, $tags) {
    global $wpdb;
    if(! is_array($post_ids) ) { 
        $post_ids = array($post_ids);
    }   
    $in_post_ids = implode("','", $post_ids);

    if(! is_array($tags) ) { 
        $tags = array($tags);
    }   
    $in_tag_names = "'" . implode("','", $tags) . "'";

    $query = "SELECT tt.term_taxonomy_id " . 
        " from $wpdb->terms as t " . 
            " JOIN $wpdb->term_taxonomy as tt ON tt.term_id = t.term_id " . 
            " JOIN $wpdb->term_relationships as tr on tr.term_taxonomy_id = tt.term_taxonomy_id " . 
        " where t.name in ($in_tag_names) " . 
            " AND (tr.object_id in ($in_post_ids)) ";
    $tt_ids = $wpdb->get_col($query); // TODO: correct function?
    $in_tt_ids = implode("','", $tt_ids);

    $delete_query = "DELETE FROM $wpdb->term_relationships where object_id in ($in_post_ids) and term_taxonomy_id in ($in_tt_ids)";
    $myrows = $wpdb->get_results( $delete_query );
}

Below is an alternate code which works:

function untag_post($post_ids, $tags) {
    global $wpdb;
    if(! is_array($post_ids) ) {
        $post_ids = array($post_ids);
    }
    if(! is_array($tags) ) {
        $tags = array($tags);
    }

    foreach($post_ids as $post_id) {
        $terms = wp_get_object_terms($post_id, 'post_tag');
        $newterms = array();
        foreach($terms as $term) {
            if ( !in_array($term->name,$tags) ) { //$term will be a wordpress Term object.
                $newterms[] = $term;
            }
        }
        wp_set_object_terms($post_id, $newterms, 'post_tag', FALSE);
    }
}

Below is the test data I used within the wordpress test environment (http://codex.wordpress.org/Automated_Testing) to test the functions:

function test_untag_post() {
    function untag_post($post_ids, $tags) {
        global $wpdb;
        if(! is_array($post_ids) ) { 
            $post_ids = array($post_ids);
        }   
        if(! is_array($tags) ) { 
            $tags = array($tags);
        }   

        foreach($post_ids as $post_id) {
            $terms = wp_get_object_terms($post_id, 'post_tag');
            $newterms = array();
            foreach($terms as $term) {
                if ( !in_array($term->name,$tags) ) { //$term will be a wordpress Term object.
                    $newterms[] = $term;
                }   
            }   
            wp_set_object_terms($post_id, $newterms, 'post_tag', FALSE);
        }   
    }   
    $post = array();
    $post['post_content'] = "Here is some content.";
    $post['post_excert'] = "Quick excerpt.";
    $post['post_title'] = "Test Post";
    $post['post_name'] = "test-post";
    $post['post_type'] = "post";
    $post_id = wp_insert_post($post);

    wp_add_post_tags($post_id, 'test-tag');
    $terms = wp_get_object_terms($post_id, 'post_tag');
    $this->assertEquals('test-tag', $terms[0]->name);

    untag_post($post_id, 'test-tag');

    $terms = wp_get_object_terms($post_id, 'post_tag');
    $this->assertEmpty($terms);
} 

EDIT: The below (which was my previous answer) IS WRONG

All that my previous answer would allow is a way to remove all post tags. But I am looking for a way to remove only specific post tags.


The function wp_delete_object_term_relationships (wp-includes/taxonomy.php line 1662) is a low level function that will do this. However...

  1. it doesn't automatically put something as uncategorized if needed (which may not be a problem)

  2. I have not tested this

  3. I feel a little uncomfortable using low level functions that are not mentioned on wordpress doc website as intended for public use.

So perhaps there is a better way.

share|improve this answer
1  
Unfortunately, quite a lot of Wordpress is undocumented for whatever reason. Sounds like that is the right tool for the job to me. Setting to uncategorized only applies to categories, having no tags is not a problem. The only other solution I can think of would be a raw MySQL query to change the term_relationships table, which seems worse than that function you found. –  miahelf Apr 17 '12 at 7:04

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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