コメントからハッシュタグをピックアップして検索可能に

 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のタグ一覧にないハッシュタグもあるので、コメント内ではリンクにしなかった。マストドンで表示する際には、一覧があれば十分な気がしたので、今回はここまでにした。

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

コメント

  1. ishii ishii より:

    コメントではなく本文の方は #WordPress のプラグイン #ActivityPub の設定の「Hashtags」の「コンテンツにネイティブタグとしてハッシュタグを追加し、タグリンクで #tag を置き換えます。」のチェックを外した状態にしてある。それは、次の所で確認したバグを避けるため。

    特定のタグが勝手に付けられるバグが再現されるかテスト | いしい@試行錯誤
    https://ishii00141.stars.ne.jp/20251224-0707-4873/

    本文で #ハッシュタグ を使わず、使ってもリンクにせずに、ハッシュタグ一覧で代用しているので、コメント欄の方もリンクにしないことにして、本文と異なりタグの選択ができないので、文章中にハッシュタグを入れてピックアップさせることにした。

  2. ishii ishii より:

    #fedibird では #WordPress 本文も含めて #ハッシュタグ がリンクになっていないと #ハッシュタグ と認識しないらしい。
    (#ハッシュタグ のミスがあったので修正した。)

    • ishii ishii より:

      mstdn.jpでも #ハッシュタグ がリンクになっていないと #ハッシュタグ として認識されないらしい。#tag の配列に追加するだけで #ハッシュタグ と認識されるのは、#Mastodon の最近のバージョンだけかも。

  3. ishii ishii より:

    #tag が空の場合に限って #ハッシュタグ を追加する仕組みにしてあるので、修正しても反映されない問題はある。
    よく起こるミスは、全角の"、"の後に半角スペースなしで #ハッシュタグ を付けてしまう場合と、ハッシュタグの終了場所に半角スペースを入れなかったり全角スペースにしてしまったり…。
    これは気を付けるしかないな。

    • ishii ishii より:

      正規表現を変更して、句読点や全角のスペース、全角の!、全角の?の後のハッシュタグもピックアップするようにした。
      修正前:

      (?<=^|\s|<p>|<br>)

      修正後:

      (?<=^|\s|<p>|<br>| |、|。|!|?)

      また、全角のスペースで終了してもピックアップするようにした。
      修正前:

      (?=\s|[\p{P}\p{S}]|$)

      修正後:

      (?=\s|[\p{P}\p{S}]| |$)

      これにより、#ハッシュタグ もピックアップされるはず。#WordPress、#ActivityPub!のように終了部分は元のままで、区切りとして認識されたらしい。#tag。

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