コメントからピックアップしたハッシュタグをリンクにして送信

 WordPressのコメントがMastodonのハッシュタグタイムラインに表示されるように、コメントからピックアップしたハッシュタグをap_outboxのpost_contentのtag配列("tag":[])に入れるフィルターフックを作成した(【コメントからハッシュタグをピックアップして検索可能に】)が、Geminiに尋ねたら、リンクにしないとハッシュタグと認識しない場合もあるとのことだった。ただし、fedibird.comやmstdn.jpではリンクになっていなくてもハッシュタグタイムラインに表示されて、mastodon.socialでは各投稿の一番下の段にhashtag-barを表示してくれる。
 ハッシュタグをリンクにした方が良いのならリンクも追加するコードに修正しようと、Geminiに相談したら、最終的にシンプルなコードで作成できた。

マストドンで表示した時にハッシュタグがリンクになっている。
修正後のマストドン(mastodon.social)での表示。(元のコメント
マストドンで表示した時にハッシュタグがリンクになっていないが、hashtag-barにピックアップしたハッシュタグが一覧として表示されてる。
修正前のマストドン(mastodon.social)での表示(元のコメント

 修正後のコードは次の通り。

/**
 * ハッシュタグ抽出用の正規表現を定義
 * (日本語対応・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. コメント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;
	}

	// 2. コメントを取得し、本文があるか確認
	$comment = get_comment( $comment_id );
	if ( ! $comment || empty( $comment->comment_content ) ) {
		return $array;
	}

	// 3. 抽出と置換(一度の処理で実行)
	$new_tags = array();
	$updated_content = preg_replace_callback( 
		MY_ACTIVITYPUB_HASHTAGS_REGEXP, 
		function( $matches ) use ( &$new_tags ) {
			$tag_name = $matches[1];
			// 日本語等のためにURLエンコードを実施
			$encoded_name = rawurlencode( $tag_name );
			
			// ドメイン/tag/タグ名/ という形式のURLを生成
			$href = home_url( user_trailingslashit( '/tag/' . $encoded_name ) );
			$esc_href = esc_url( $href );
			
			// ピックアップしたタグが存在しない場合に$new_tagsに追加
			if ( ! isset( $new_tags[$tag_name] ) ) {
				$new_tags[$tag_name] = array(
					'type' => 'Hashtag',
					'href' => $esc_href,
					'name' => '#' . $tag_name,
				);
			}
			
			// ハッシュタグにリンクを付加
			return sprintf( '<a href="%s" class="hashtag u-tag u-category" rel="tag">#%s</a>', $esc_href, esc_html( $tag_name ) );
		}, 
		$comment->comment_content 
	);

	// 4. 解析結果を反映(空の場合も含めて上書きする)
	$array['tag'] = array_values( $new_tags );
	$formatted_content = wpautop( $updated_content );
	$array['content'] = str_replace( array( "\r\n", "\r", "\n" ), '', $formatted_content );

	return $array;
}, 10, 4 );

未分類
管理人のマストドンアカウントへのリンクなど

コメント

  1. ishii ishii より:

    #Mastodon v4.6.0-nightly.2026-01-16
    #WordPress のコメントの最後に空白行を挟んで #ハッシュタグ 一覧を書いておくと、mastodon.socialではhashtag-barに変換してくれるのだが、その際に、コメント本文内にあるハッシュタグは省略される。#ハッシュタグ がリンクになっていなかった時は、コメントに書いたとおりのハッシュタグ一覧が残るが、その下にhashtag-barがあるから、無駄に感じる。
    #fedibird やmstdn.jpではhashtag-barは作成しないので、コメント欄の一番下にハッシュタグ一覧を書いておくと、hashtag-barの代わりになる。ただし、リンクにしておかないと、クリックしても #ハッシュタグ をクリックしたことにならない。

    (このコメントでも一番下にハッシュタグ一覧を書いておいたが、<pre><code>タグで囲んでいて、半角スペースで囲まれていない#Mastodon#fedibirdはリンクになっていないと思う。)

    #Mastodon #WordPress #ハッシュタグ #fedibird
    • ishii ishii より:

      #Mastodon v4.6.0-nightly.2026-01-16
      このケースでは、一番下の #ハッシュタグ 一覧で、#Mastodonはリンクになっていなかったが、#fedibirdはリンクになっていた。正規表現でハッシュタグの終了部分の判定に記号が含まれていて、<も記号と認識されているからかもしれない。ただし、#ハッシュタグ の前は、<p>と<br>以外のタグではダメ。

      #WordPress #Mastodon #ハッシュタグ

      • ishii ishii より:

        #ハッシュタグ の前の区切りとして、<p>と<br>だけでなく<code>も追加したくなったが、今後、<code>内はリンクにしないように修正する可能性があるので、やめた。

        #WordPress #Mastodon #ハッシュタグ

タイトルとURLをコピーしました