WordPress bringt für die programmatische Zuweisung von Taxonomien zu einem Post (beispielsweise einem Bild) eine wunderbare Funktion mit:

Die Funktion hat allerdings ihre Tücken. Zum einen prüft sie nicht, ob zwischen dem Post und der Taxonomie (bereits) eine Verbindung besteht. Dies wird auch näher beschrieben in einem WordPress Entwickler Post.
Es gibt aber noch zwei kleine Kuriosen worüber man stolpern kann. Das Erste genau dann, wenn man versucht, nacheinander verschiedene Terms zu einem Post mit Hilfe dieser Funktion zuzufügen. Und zwar in dem Fall einzeln nacheinander und nicht etwa per array.
In dem Fall landet in der Datenbank lediglich eine der Relationen. Hat man drei Relationen, fallen so also 2 einfach unter den Tisch.
Lösung: Hier auf jeden Fall die entsprechenden Terms in ein Array packen und das Array übergeben. Dann werden alle Relationen beachtet.
Das zweite Kuriosum betrifft den Umgang mit übergebenen Werten.  Wenn man (entweder im Array oder als Einzelwert) den Inhalt der Variable, mit dem man den Term übergibt nicht explizit typisiert, kann es passieren, dass einige der Terms, die mit einer ID übergeben werden, als Zeichenkette (string) betrachtet werden und somit dann unerwartete Ergebnisse liefern.
Lösung: die entsprechende Übergabe explizit mit einem Typ versehen also z.B. (int)$term_id für Einzelwerte oder falls man es in ein Array packt dann z.B. so: array_push($term_ids,(int)$term_id);
Mit diesen „Vorsichtsmaßnahmen“ verhält sich die Funktion dann so, wie man es vermutlich erwartet. Bedenklich finde ich es aber schon ein wenig, da an der Stelle offenbar schlecht überprüft wird, was in $term_id wirklich drin steckt. Anders ausgedrückt: Ich wäre sehr vorsichtig damit, was ich der Funktion übergebe… Vielleicht werde ich auch in der kommenden Zeit nochmal Gelegenheit finden auszuprobieren, was passiert, wenn man einen nicht sauberen String in die Terms übergibt…