The Codex has almost exactly what you are asking:
$args = array(
'post_type' => 'post',
'tax_query' => array(
'relation' => 'AND',
array(
'taxonomy' => 'movie_genre',
'field' => 'slug',
'terms' => array( 'action', 'comedy' )
),
array(
'taxonomy' => 'actor',
'field' => 'id',
'terms' => array( 103, 115, 206 ),
'operator' => 'NOT IN'
)
)
);
$query = new WP_Query( $args );
You just need to remove the couple of parts you don’t need, and of course change the post_type and taxonomy details to fit your data.
$args = array(
'post_type' => 'post',
'tax_query' => array(
array(
'taxonomy' => 'post_tag',
'field' => 'id',
'terms' => array( 103, 115, 206 ), // change these
'operator' => 'NOT IN'
)
)
);
$query = new WP_Query( $args );
Best I can do with the minimal detail provided in the question.
Based on new information in an edit to the question:
The 'tag' => $rel_tagnames, pattern you are using is deprecated. You should be using a tax_query as above. Since you are already including a list of tags to search, you shouldn’t need to exclude any. When you include specific tags, others are de facto excluded. So what you would want is this:
if ($rel_tags) {
$relatedargs = array(
'ignore_sticky_posts' => 1,
'post__not_in' => array($id),
'showposts' => $relatednumber,
'orderby' => 'rand'
);
// Get list of tag names and set arguments for loop
foreach($rel_tags as $rel_tag) {
// exclude some tags
$excluded_tags = array (1,2,3);
if (in_array($rel_tag->term_id,$excluded_tags)) continue;
$rel_tagnames[] = $rel_tag->term_id;
}
$relatedargs['tax_query'] = array(
array(
'taxonomy' => 'post_tag',
'field' => 'id',
'terms' => $rel_tagnames,
)
)
}
// the rest of your code
I changed that to use IDs instead of slugs. It is probably more efficient to search those than the slugs, though I haven’t benchmarked it, and converted to a tax_query. Tags are excluded when you build the “include” list, instead of trying to do that in the query itself.
Why does your function set globals instead of just returning data?