WorPressのプラグインActivityPubではコメント欄のハッシュタグをリンク形式にする機能はあっても、マストドンのハッシュタグタイムラインを見ると、そのコメントが対象外になっている。それは、Fediverseに送信したJSONのtagが空("tag":[])だからで、wp_postsテーブルのpost_typeがap_outboxのpost_contentを見れば確認できる。だから、コメントからピックアップしたハッシュタグをJSONのtagに入れて、マストドンのハッシュタグタイムラインに表示されるようにした。
標準では、日本語のハッシュタグはピックアップしてくれないし、数字だけでもハッシュタグにしちゃうし、カラーコードもハッシュタグにしちゃうので、ピックアップするための正規表現は独自に作った。
さて、includes/activity/class-generic-object.php を見ると、次のコードがある。
/**
* Filter the array of the ActivityPub object.
*
* @param array $array The array of the ActivityPub object.
* @param string $class The class of the ActivityPub object.
* @param string $id The ID of the ActivityPub object.
* @param Generic_Object $object The ActivityPub object.
*
* @return array The filtered array of the ActivityPub object.
*/
$array = \apply_filters( 'activitypub_activity_object_array', $array, $class, $this->id, $this );
Geminiによると、「このコードは、WordPressの「フィルターフック」という仕組みを使って、ActivityPub(MastodonやMisskeyなどの分散型SNSと通信するプロトコル)へ送信するためのデータを最終調整している箇所」らしい。すなわち、フィルターフックを利用して、$arrayの中にある"tag"を修正できるということらしい。そして、Geminiと相談して作ったコードが次の通りで、テーマファイルエディターの functions.php に追加した。
/**
* ハッシュタグ抽出用の正規表現を定義
* (日本語対応・HTMLタグ直後対応・数字のみ拒否)
*/
// ポイント:
// 1. (?![\d\p{P}]+(?:\s|$)) : 数字と記号のみの構成を拒否
// 2. ((?:[^\s\p{P}\p{S}]|_)+) : タグ本体(日本語を含む)
// 3. (?![^#\s]*;) : タグの塊の「直後」にセミコロンがあることを許さない
// 4. (?=\s|[\p{P}\p{S}]|$) : 境界の再確認
define( 'MY_ACTIVITYPUB_HASHTAGS_REGEXP', '/(?<=^|\s|<p>|<br>)#(?![\d\p{P}]+(?:\s|$))((?:[^\s\p{P}\p{S}]|_)+)(?![^#\s]*;)(?=\s|[\p{P}\p{S}]|$)/u' );
/**
* ActivityPubのオブジェクト配列にカスタムハッシュタグを挿入する
*/
add_filter( 'activitypub_activity_object_array', function( $array, $class, $id, $object ) {
// 1. すでにtagがある(または空でない)場合は終了
if ( ! empty( $array['tag'] ) ) {
return $array;
}
// 2. コメントIDを特定
$comment_id = null;
// JSON内の 'id' (例: https://.../?c=1304) から数字を抽出
if ( isset( $array['id'] ) && preg_match( '/[?&]c=(\d+)/', $array['id'], $id_matches ) ) {
$comment_id = $id_matches[1];
}
// フォールバック: 引数の $id が数値ならそれを利用
elseif ( is_numeric( $id ) ) {
$comment_id = $id;
}
if ( ! $comment_id ) {
return $array;
}
// 3. コメントを取得し、本文があるか確認
$comment = get_comment( $comment_id );
if ( ! $comment || empty( $comment->comment_content ) ) {
return $array;
}
$text = $comment->comment_content;
// 4. ハッシュタグの抽出と配列化
if ( preg_match_all( MY_ACTIVITYPUB_HASHTAGS_REGEXP, $text, $matches ) ) {
$tags = array();
$unique_tags = array_unique( $matches[1] ); // 重複を排除
foreach ( $unique_tags as $tag_name ) {
// 日本語等のためにURLエンコードを実施
$encoded_name = rawurlencode( $tag_name );
// ドメイン/tag/タグ名/ という形式のURLを生成
$href = home_url( user_trailingslashit( '/tag/' . $encoded_name ) );
$tags[] = array(
'type' => 'Hashtag',
'href' => esc_url( $href ),
'name' => '#' . $tag_name,
);
}
// 5. tag配列を上書き(代入)
if ( ! empty( $tags ) ) {
$array['tag'] = $tags;
}
}
return $array;
}, 10, 4 );
このコードで試した結果、マストドンでは次のように表示された。ハッシュタグはリンクにならないが、ハッシュタグの一覧は下に表示されるようになった。

ハッシュタグをリンクにすることもできるが、WordPressのタグ一覧にないハッシュタグもあるので、コメント内ではリンクにしなかった。マストドンで表示する際には、一覧があれば十分な気がしたので、今回はここまでにした。

コメント
コメントではなく本文の方は #WordPress のプラグイン #ActivityPub の設定の「Hashtags」の「コンテンツにネイティブタグとしてハッシュタグを追加し、タグリンクで #tag を置き換えます。」のチェックを外した状態にしてある。それは、次の所で確認したバグを避けるため。
特定のタグが勝手に付けられるバグが再現されるかテスト | いしい@試行錯誤
https://ishii00141.stars.ne.jp/20251224-0707-4873/
本文で #ハッシュタグ を使わず、使ってもリンクにせずに、ハッシュタグ一覧で代用しているので、コメント欄の方もリンクにしないことにして、本文と異なりタグの選択ができないので、文章中にハッシュタグを入れてピックアップさせることにした。