WordPressサイトをMastodon, Misskeyからフォローできるようにしよう ―ActivityPubプラグインを使ってみる―

# イントロ
かつて青い鳥がいた某SNSに、人々は集まっていました。しかし最近のあまりの混乱ぶりに、人々は他のSNSへと分散していきました。

ある人はMastodonへ、ある人はMisskeyへ[^instance]。Fediverseという宇宙 [^fediverse] へと旅立っていきました。これらは別々の星（サーバー）にありながら、相互に通信することができるという性質を持っています。これは[ActivityPub](https://www.w3.org/TR/2018/REC-activitypub-20180123/)と呼ばれる共通のプロトコル（通信規約）を実装しているからです。

[^instance]: Mastodon, Misskeyなどは厳密にはサーバーのソフトウェア名です。実際にはそれぞれのソフトウェアを実行するサーバーが複数あり、各ユーザーは所属するサーバー（インスタンスとも）を選んでアカウントを作成します。Misskeyならmisskey.io, misskey.art, misskey.design, ... などがあります。ここではあえて厳密さは追求しません。

[^fediverse]: Federation（連合）と Universe（宇宙）を組み合わせた造語。異なるサーバー同士が接続することを連合と呼んでいます。

## 繋がれるのはSNSだけではない
Mastodon, Misskeyなどのサーバーは共通のプロトコルで通信していると書きました。このプロトコルを実装することにより、一般的にいわゆる「SNS」に分類されないものでも繋がることができてしまいます。その中で最近一部で注目を集めているのが、ブログシステムの「WordPress」です。そう、**WordPressとMastodonは相互フォローできるのです。**

論より証拠、私のmisskey.designのアカウント ([@monaco_koukoku@misskey.design](https://misskey.design/@monaco_koukoku)) のフォロー欄を見てみましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204084/6c0619be-8b8e-d4cc-297f-ea7e22d5bcc9.png)

アカウント名は ``@monaco@monaco.every-little.com`` となっています。真ん中の @ より後ろがサーバーのドメイン名（サーバーを越えて相互フォローできるので、アカウントを一意に区別するためにドメイン名をつける）です。**このドメイン名というのは、[私のWordPressサイト](https://monaco.every-little.com/)のそれにほかなりません。**

https://monaco.every-little.com/

このアカウントをクリックすると、misskey.designの画面からは以下のようにノート（投稿）が表示されます。ぱっと見は特に違和感なく見えますね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204084/1122bbc4-e5dc-f9e9-99a5-49cb65d6fe7a.png)

このノートの実体は、[WordPressに投稿した記事](https://monaco.every-little.com/archives/407)です。つまり、このアカウントをフォローしているMastodon, Misskeyなどのアカウントは、WordPressに投稿した新着記事の情報をタイムラインで見ることができます。例えば、私の場合は同人誌即売会に参加（出店）しているので、Webサイトに参加するイベント情報を投稿することで、MastodonやMisskeyなどのユーザーにも告知することができます。

この記事では、以上のようにWordPressをMastodon, Misskeyなどが動く各サーバーからフォローできるようにする方法について書きます。なお、この分野は移り変わりが激しいので、日が経つとこの記事の内容が適用できなくなるかもしれません。あらかじめご了承ください。

# 検証環境

- WordPress v6.3.2
    - ActivityPubプラグイン v1.0.10
    - （オプション）NodeInfoプラグイン v2.2.0

また、WordPressサイトが以下の条件を満たしていることを前提とします。
- 独自ドメイン（サブドメイン可）が設定されていること
- HTTPSが有効化されていること（Let's Encrypt可）
- WordPressがルートディレクトリにセットアップされていること（``https://example.com/`` のようなドメイン名だけのアドレスでWordPressサイトのトップページにアクセスできる）
    - この条件については回避できなくもないようですが、この記事では省略します

# 準備

WordPressにActivityPubプラグインをインストールします。管理画面の **「プラグイン」→「新規追加」** をクリックし、検索窓に **ActivityPub** と入力し、このピンクのアイコンのものをインストールします。インストールが終わったらプラグインの有効化をお忘れなく。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204084/01918be1-6dc6-2362-26d1-abbea26cf0a6.png)

# 最小限のセットアップ

**以上です。**

アカウント名はWordPressのユーザー名になります。外部から見たときのアカウント名は、ドメイン名を加えて ``@(WordPressのユーザー名)@(ドメイン名)`` となります。おそらくMastodonの検索窓などにこの文字列を入れると、サイトがヒットすると思います。

しかしデフォルト設定では色々具合が悪いので、アカウント名を他の方に教える前にちゃんと設定しておきましょう。

# もう少しちゃんとしたセットアップ

WordPressの管理画面を開き、ActivityPubプラグインの設定画面から操作します。

## アカウントの種類

企業や団体ではWordPressのサイトを複数人で運営することがあると思います。このようなケースのために、ActivityPubプラグインでは以下の2種類のアカウントを公開できるようになっています。

- WordPressユーザー個人のアカウント
    - WordPressのユーザー名がアカウント名になる（デフォルトで有効化されるのはこちら）
    - フォロワーのタイムラインでは各個人が投稿した記事のみが見える
- サイト全体のアカウント
    - 好きな文字列をアカウント名にできる（WordPressユーザー名と重複しないこと）
    - フォロワーのタイムラインでは全ユーザーが投稿した記事が見える

これらは両方有効化することもできますし、一方のみを有効化することもできます。**「設定」** タブの **「プロフィール」** のうち、**「投稿者を有効化」** にチェックを入れると前者が、**「ブログを有効化」** にチェックを入れると後者が有効化されます。

![1cdf83ebbe0fc9d1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204084/3d9bae1d-6826-7833-4d7e-619e6c29415b.png)

サイトを個人で運用している場合、どちらのアカウントも実質的に同じです。その場合、後者だけを使うのが楽だと思います。**「投稿者を有効化」** のチェックを外し、**「ブログを有効化」** のチェックを入れます。さらに、**「ブログプロフィールIDを変更」** にアカウント名にしたい文字列を入力します。

ただし、**一度運営を始めて誰かからフォローされているアカウントの場合、アカウント名を変えるとフォロワーさんが見つけられなくなってしまいます。** アカウント名は人に宣伝する前に確定させておきましょう。

これ以降は、**サイト全体のアカウントを前提とした説明** となります。

## タイムラインに表示される内容の設定

ブラウザの画面を下にスクロールすると **「アクティビティ」** という項目があります。

![f26b34acf8379663.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204084/2acd5efd-086e-3971-ab94-5f7d1cc49bc6.png)

**「投稿コンテンツ」** で、投稿される内容をカスタマイズできます。私の場合「カスタム」を選択し、以下の内容を入力しています。
```html
<strong>[ap_title]</strong>

[ap_excerpt]

[ap_hashtags]

<a href="[ap_permalink]">[ap_permalink]</a>
```

タグの意味については「ActivityPub テンプレートタグの一覧を見る。」のリンクから確認できますが、おそらくなんとなく察しはつくのではないでしょうか。この設定をすることで、以下のページが冒頭の画像（以下に再掲）のような投稿として見えるようになっています。

https://monaco.every-little.com/archives/407

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204084/1122bbc4-e5dc-f9e9-99a5-49cb65d6fe7a.png)

**「画像数」** については大きめの値にしておくのがよいです。画像ではデフォルト値「3」となっていますが、「3」と書いても実際には1枚しか表示されないケースがありました。余裕をもって「10」くらいでも良いと思います。

## アバター画像

アカウントのアバター画像としては、テーマのカスタマイズ画面から設定できる **「サイトアイコン」** が使われます。512×512のPNG形式などでアイコン画像をご用意ください。同じ画像が自動的にWordPressサイトのFaviconにも設定されます。

![3019fc1265b2b29f.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204084/b42818b3-0659-a353-1957-4c313e3f140d.png)

# 想定通りの表示になるか確認

ここまで設定できたら、想定通りの投稿内容が生成されるか確認しましょう。しかし、フォロワーさんのタイムラインに配信されるのは、これから新しく投稿する記事だけです（メルマガのイメージに近いですね）。テスト用に何度も投稿するのはサイトを汚してしまって良くないので、既存の記事がどのように表示されるか見る方法を説明します。

## ActivityPubプロトコルとしての配信内容を確認する

URLをMastodonの検索窓などに入れれば確かに表示は確認できるのですが、一度サーバーが投稿をキャッシュしてしまうと、配信内容を修正・変更したとしても反映されなくなってしまいます。そのため、まずはプロトコルとしての配信内容を見ておくのが良いです。

私のドメイン名 ``monaco.every-little.com`` の場合、これまでに投稿した記事から変換されたノートの情報を以下のURLから得ることができます。

``https://monaco.every-little.com/wp-json/activitypub/1.0/users/0/outbox``

このURLにアクセスするとJSON形式のデータが返ってきます。ブラウザで表示する場合、Chrome拡張機能の「JSON Formatter」などを使うと見やすく整形することができます。Firefoxの場合はデフォルトで整形表示されるので便利です。

JSONオブジェクトの ``orderedItems`` に、各投稿の情報が入っています。0番が最新の投稿、1番がその次に新しい投稿、という感じになっています。詳細はActivityPubの仕様書に譲りますが、ここではおよそ以下の図に示した部分（特に画像と本文の内容）が想定通りかをチェックすればよいでしょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204084/0ab0ae2f-d366-1695-9bf0-126d8b0e27b4.png)

もし想定通りでない点があれば、画像数の設定や「投稿コンテンツ」の設定を変更して、URLをリロードします。

## 表示される画像について

記事に指定した **アイキャッチ画像** が1枚目の画像として添付され、それ以降は記事に貼り付けた画像が添付されます。同じ画像が複数枚存在する場合（アイキャッチ画像と本文画像の場合も含む）、最初の1枚のみがノートに表示されます。

## ハッシュタグについて

記事の **「タグ」** に指定したものが、ハッシュタグとしてノートに追加されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204084/3f6c3f98-ba90-38ee-a0b0-230d9278391b.png)

## [ap_excerpt] タグから展開される抜粋について

記事の **「抜粋を入力」** に入力されていればその内容が入り、入力されていなければ自動生成された抜粋が使用されます。ただし、**WordPressの自動抜粋機能は多言語対応が怪しい**（日本語の場合、上限を「50単語」に指定すると「50文字」で切られたりする）ので、手動で「抜粋」の内容を埋めることをおすすめします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204084/17ff0740-3185-113f-6208-c69aa898aac4.png)

## 実際にフォローして確認してみる

うまく調整できたら、実際にご自身のMastodonやMisskeyアカウント（メインアカウントとは別に、テスト用に作るのも良いでしょう）からWordPressサイトをフォローし、WordPress側で何か記事を投稿してみてください。記事のステータスが「公開」になったタイミングでノートが作られ、タイムラインに配信されます。

**一度配信された記事に対する修正は、Fediverse側のノートには反映されません。またノートを削除するには、記事をゴミ箱に送る必要があります（下書きに戻しても消えないようです）。**

# さらなる改良（上級者向け）

これでだいたいの体裁は整ったのですが、よく見るとプロフィール欄やサーバー情報にもう少し改良の余地がありますので、もうひと手間加えてみます。

**ここからはプラグインのPHPコードを直接変更する必要があります。変更箇所が勝手にロールバックされないよう、ActivityPubプラグインの自動更新の無効化を推奨します。**

## 表示名・プロフィール欄

サイト全体としてのアカウントを運用する場合、**WordPressのサイト名・キャッチフレーズに入力した内容（以下の画像参照）が、そのままFediverseから見たユーザの表示名とプロフィール文になります。**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204084/6d88b801-0313-0c5e-2093-946b1f64d5ce.png)

しかしキャッチフレーズって一言で書くものですから、プロフィール欄に書く内容としては短すぎます。表示名についても、サイト名そのままよりは「告知用」などと付け加えたい場合があります。これらのカスタマイズ機能はプラグインに（執筆時点では）備わっていないので、変更するにはプラグインのコードに手を入れなければなりません。

ActivityPubのプラグインファイルエディターで ``activitypub/includes/model/class-blog-user.php`` を開き、画像で示した箇所を変更します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204084/d9605022-88b4-f843-b8a3-2e164d81bc0a.png)

```php
	public function get_summary() {
		$home_url_escaped = esc_url( home_url( '/' ) );
		return \wpautop(
			\wp_kses(
				\get_bloginfo( 'description' ) . ' / Webサイト <a href="' . $home_url_escaped . '">' . $home_url_escaped . '</a> の新着記事を配信します / お問い合わせは <a href="https://misskey.design/@monaco_koukoku">@monaco_koukoku@misskey.design</a> まで',
				'default'
			)
		);
	}
```

``\get_bloginfo( 'name' )`` がサイト名、``\get_bloginfo( 'description' )`` がキャッチフレーズです。オリジナルの内容を活かしても良し、これらの関数を使わずに文字列をフリー記述するも良しです。

変更内容はアカウント情報を参照するサーバーによってはすぐに反映されず、1日程度掛かる場合があるようです。気長に待ってみてください。

## サーバー情報

Mastodonユーザーの方はあまり意識しないかもしれませんが、Misskey, Firefishなどが動くサーバーでは、タイムラインや個別ノートの表示において、ユーザー名の下や横にそのユーザーが属するサーバーの情報が表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204084/b3b414ca-3621-3eee-1715-67543b1f6704.png)

しかしWordPressのActivityPubプラグインでは、現状この情報が提供されておらず、Misskeyなどから見た時にサーバー名が空白で表示されてしまいます。

↓こうなってしまう。
![e85853807b554742.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204084/aaa5d30f-772d-7270-2e45-80e67718266c.png)

ここではこの問題を回避する改造を行います。

WordPressにNodeInfoプラグインをインストール・有効化します（自動更新の無効化を推奨）。
NodeInfoのプラグインファイルエディターで ``nodeinfo/includes/class-nodeinfo.php`` を開き、画像で示した2行を追加します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204084/121332f0-02e8-e0ad-b9fe-8885aeb2e3e5.png)

```php
		$metadata['nodeName'] = get_bloginfo('name');
		$metadata['nodeDescription'] = get_bloginfo('description');
```

こちらも変更内容の反映には数日程度掛かるケースがあるようです。うまくいけば、WordPressのサイト名がサーバー名として表示されるようになるはずです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204084/59038a6c-3bbf-3e5c-b3c9-945684142fe7.png)

# その他

## 誰からフォローされているか確認したい

ActivityPubプラグインの設定画面にある「フォロワー」タブから確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204084/f793f06f-4564-c918-7321-fc106d6bfd31.png)

## WordPress側からも他のユーザーをフォローしたい

「[Friends](https://ja.wordpress.org/plugins/friends/)」というプラグインをインストールするとよいらしいです。（とプラグインの設定ページに書いてありました）
個人的に未検証（使っていない）なので、詳細は割愛します。

# 最後にお知らせ

冒頭の画像にも出ていましたが、2023年11月11日（土）に開催される「[文学フリマ東京37](https://bunfree.net/event/tokyo37/)」に出店します。
マルフク看板やキリスト看板など、街で気になったものたちを題材に本を作っています。お近くの方、よろしくお願いいたします。

↓Webカタログです。

https://c.bunfree.net/e/ais

他のイベント参加情報については、近くなりましたら ``@monaco@monaco.every-little.com`` で配信します。それでは。