解 説

is_category() と in_category() と has_category()の使い分けについて考えてみます。
どれも引数に指定したカテゴリがあるかどうか判定する条件式で使用されます。

どう使い分けるのか?

WordPress Codexの記述は次の通りです。

is_category
この条件分岐タグは、カテゴリーアーカイブが表示されているかチェックします。 TRUE または FALSE を返すブール関数です。
in_category
現在の投稿(あるいは指定した任意の投稿)に、指定したカテゴリーが割り当てられているか調べます。
in_category() は、投稿に直接割り当てられているカテゴリー(管理画面の新規投稿/編集でチェックしたカテゴリー)のみを考慮します。 しかし、そのカテゴリーの親は考慮しません(用例の「子カテゴリー内の投稿かテストする」も参考にしてください)。
このタグは、ループ内で現在の投稿をテストできます。 また(バージョン 2.7 以降で)単一投稿リクエストの場合にループ外でも使えます。 テストしたい投稿を指定すれば、どこでも使用できます。
has_category
現在の投稿が指定されたカテゴリーを持っているかチェックします。
指定されたカテゴリーは、投稿に付けられたカテゴリーの ID、名前、スラッグに合うかチェックされます。 整数で指定されたカテゴリーは、投稿のカテゴリーの ID のみと比較されます。
カテゴリーが指定されない場合は、投稿が任意のカテゴリーを持つかチェックします。

is_category()は現在表示しているページが引数で指定したカテゴリのアーカイブページかどうかを判断します。
has_category()は現在表示しているページが引数で指定したカテゴリのページ(シングルページでもよい)になっているかどうかを判断します。

それで、色々試してみました。
次のコードのif文の条件をis_category() と in_category() と has_category()それぞれ変更しました。

is_category() の違い

アーカイブのページのループ文内に挿入した場合は3つの条件どれも同じ結果になります。
つまり「ドリンク」のカテゴリの記事に、h1の《「飲み物」に関する記事》が表示されます。

投稿の個別ページのループ文内に挿入した場合は変化があります。
is_category()で判定したもはh1の「飲み物」が表示されません。
in_category() と has_category()の判定では、どちらも個別ページにh1の「飲み物」が表示されます。

is_category()はカテゴリーアーカイブが表示されているかチェックします。 とCodexの記述のとおりアーカイブのページで使用するもので、個別のページでは使用できないことがわかります。

in_category() と has_category()の違い

has_category()はバージョン 3.1.0 にて導入されたものですが、in_category() と同じように使えています。

has_category() 現在の投稿が指定されたカテゴリーを持っているかチェックします。
in_category() 現在の投稿(あるいは指定した任意の投稿)に、指定したカテゴリーが割り当てられているか調べます。

はい、現在違いを究明中です。