WordPressのプラグインActivityPubが7.6.0に更新されてから、マストドンで表示される日本語のハッシュタグがエンコード文字列から%が抜けたハッシュタグになるバグが発生しているが、解決策が分かったかもしれない。
まず、/activitypub/includes/transformer/class-post.php のコードの「'name' => esc_hashtag( $post_tag->slug )」が怪しく、「'name' => esc_hashtag( $post_tag->name )」にすべきではないかと検討したが、「 $post_tag->slug 」でなければいけない理由があった。それは、WordPressのタグには「Test for tags with spaces」のように半角スペースが含まれていることがあり、wp_terms テーブルの「name」はタグそのままなので処理しにくいのかもしれない。「slug」であれば、「test-for-tags-with-spaces」と"-"で繋がる。

また、「'name' => esc_hashtag( $post_tag->name )」で試してみたが、esc_hashtag()関数に渡された時点でURLエンコードされていて「slug」で渡したのと同じ状態だったらしく、結果が同じだった。したがって、「'name' => esc_hashtag( $post_tag->slug )」のままで対策を考える必要がある。「slug」は単語の先頭の文字が小文字になるので、それが気に入らないが…。
さて、esc_hashtag()関数を修正するわけだが、前回の記事にあるようなGeminiの考察を読み直して、次のコードが問題ではないかと考えた。
$hashtag = \preg_replace( '/emoji-regex(*SKIP)(?!)|[^\p{L}\p{Nd}-]+/u', '-', $hashtag );
[^\p{L}\p{Nd}-]+ という部分が「(文字、数字、ハイフン)ではないすべての文字」を意味していて、それを"-"に置換するコードらしい。このコードで"%"も"-"に置換されるらしい。"%"が消えたのは、このコードが原因だと考えるのが妥当だから、"%"が"-"に置換されないように、次のようにコードを修正した。
$hashtag = \preg_replace( '/emoji-regex(*SKIP)(?!)|[^\p{L}\p{Nd}\-%]+/u', '-', $hashtag );
ちなみに、この後、"-"は単語の区切りとして認識され、"-"の後ろのアルファベットが大文字にされて、"-"は削除されるらしい。例えば、WordPressのタグ「Test for tags with spaces」はslugの「test-for-tags-with-spaces」が使われ、マストドンのハッシュタグは「#testForTagsWithSpaces」になる。
さて、これだけだと、マストドンではURLエンコードされたままでハッシュタグになってしまう。ap_outboxのためのJSONに入れる際に、Unicodeエスケープされていないといけないのだが、URLエンコードされたままの文字はUnicodeエスケープされないらしい。また、esc_hashtag()関数内でUnicodeエスケープする必要はなく、デコードされた日本語で渡せば、外部でUnicodeエスケープしてくれるらしい。
そこで、esc_hashtag()関数の最後の「return esc_html( $hashtag );」の前に「$hashtag = urldecode( $hashtag );」を追加して次のようにする。
$hashtag = urldecode( $hashtag );
return esc_html( $hashtag );
これで試したところ、WordPressの「テスト」というタグはマストドンで「#テスト」と表示された。

この変更はプラグイン「ActivityPub」のコードを変更しちゃっているので、本当は元に戻した方が良いのだが、いつまで経っても修正されない可能性があるので、このままにする。アップデートされたら、ファイルが丸ごと変更されて、問題生じないだろうと思うことにする。


コメント
apply_filters( 'activitypub_esc_hashtag', $hashtag, $input )があるので、
テーマの functions.phpに次のコードを追加すれば、元の関数のソースコードは変更しなくて良いらしい。 #ChatGPT の回答。