Skip to content

API-007 X告知 REST ​

← API-一覧

概要 ​

X告知担当 bot が、公開済みの日別記事・有料記事を X で告知するための REST。告知に使う記事のメタ情報(URL・タイトル・考察日・号数・アイキャッチ URL 等)を読み、X に投稿した結果(告知履歴)を記事に書き戻す。X告知担当ロール(x_announcer、Capability read_x_announce / record_x_announcement)のユーザーがアプリケーションパスワードで呼ぶ。

  • 返す項目は許可リストで固定する。本文(post_content)・考察欄・抜粋・有料記事の冒頭挨拶やセクション・任意の post meta は返さない。告知文の要約は各記事の編集 bot が作る
  • 公開済み(publish)の記事だけを対象にする。下書き・予約・非公開は一覧に出さず、1 件取得と記録は 404
  • 書き込みは告知履歴の記録(API-007-5)だけ。記事本体は変更しない
  • X への投稿は bot 側で行う。X の API キー・アクセストークンは bot のシークレットに置き、WordPress には保存しない
  • bot が X API で投稿するか人間が投稿するかは、管理画面(ADM-036)で記事の種類ごとに設定し、bot は API-007-6 で読む。bot からは変更できない
  • 運用確認・日別記事編集・取込用の REST とは namespace を分ける。アカウントとアプリケーションパスワードも分ける

日別記事の項目 ​

field型説明
idint投稿 ID
urlstringパーマリンク
titlestringタイトル
kousatsu_datestring考察日(Y-m-d。Ymd で保存されている場合も Y-m-d に揃える)
published_gmtstring公開日時(GMT、Y-m-d H:i:s)
modified_gmtstring更新日時(GMT、Y-m-d H:i:s)
featured_image_urlstring|nullアイキャッチ画像の URL(full)。無ければ null。添付するかは bot が決める
announcementsarray告知履歴(下記)。古い順

有料記事の項目 ​

日別記事の kousatsu_date の代わりに次を持つ(他は同じ)。

field型説明
issue_numberint|null号数(PaidArticleMetaKeys::ISSUE_NUMBER)。未設定は null
target_monthstring対象月(PaidArticleMetaKeys::TARGET_MONTH)。未設定は空文字
is_free_releasebool無料公開中か(PaidArticleMetaKeys::IS_FREE_RELEASE が 1)

告知履歴の項目 ​

記事ごとに protected meta _x_announcements(JSON 配列、古い順)へ保存する。21 件目を記録すると最も古い行を消し、最新 20 件だけ残す(XAnnouncementConstants::MAX_ENTRIES_PER_POST)。

field型説明
kindstringdaily_pre(示唆考察)/ daily_after(結果考察)/ paid_update(有料記事)
tweet_idstringX の投稿 ID(数字だけ)
tweet_urlstringhttps://x.com/i/web/status/{tweet_id}
posted_atstringX に投稿した日時(UTC、Y-m-d\TH:i:s\Z)
recorded_atstringWordPress に記録した日時(UTC、Y-m-d\TH:i:s\Z)

保存値が壊れている・項目が欠けている行は返さない。

API-007-1 GET /daily-articles ​

入力(リクエスト) ​

param必須型・制約説明
date_fromはいY-m-d考察日の開始日(含む)
date_toはいY-m-d考察日の終了日(含む)

期間は両端を含めて最大 31 日(XAnnounceRestController::MAX_RANGE_DAYS)。

出力(レスポンス) ​

field型説明
successbooltrue
date_fromstring開始日
date_tostring終了日
countintitems の件数
truncatedbool上限で打ち切ったか
itemsarray日別記事の項目。考察日・ID の昇順

HTTP ステータス: 200。1 回の取得は最大 200 件(XAnnounceArticleReaderInterface::DAILY_LIST_LIMIT)。超えるときは投稿 ID の小さい順に 200 件を返し、truncated を true にする。期間を分けて取り直すこと。

失敗・エラー条件 ​

条件HTTPmessage
どちらかが無い・Y-m-d でない・存在しない日付400XAnnounceRestCopy::DATE_RANGE_REQUIRED
date_from が date_to より後400XAnnounceRestCopy::DATE_RANGE_ORDER_INVALID
期間が 31 日を超える400XAnnounceRestCopy::DATE_RANGE_TOO_LONG

API-007-2 GET /daily-articles/{id} ​

入力(リクエスト) ​

param必須型・制約説明
idはい正の整数(パス)日別記事の投稿 ID

出力(レスポンス) ​

field型説明
successbooltrue
itemobject日別記事の項目

HTTP ステータス: 200

失敗・エラー条件 ​

条件HTTPmessage
id 不正400Messages::REST_INVALID_ID_MESSAGE
日別記事でない・公開済みでない・存在しない404XAnnounceRestCopy::DAILY_ARTICLE_NOT_FOUND

API-007-3 GET /paid-articles ​

入力(リクエスト) ​

param必須型・制約説明
modified_afterいいえISO 8601(タイムゾーン必須、小数秒は任意)、または modified_gmt と同じ Y-m-d H:i:s(UTC として扱う)この日時より後(含まない)に更新された記事だけ返す

modified_after は UTC に直して post_modified_gmt と比べる。前回取得時の modified_gmt をそのまま渡せば、更新された有料記事だけを取れる。タイムゾーンのオフセットは ±14:59 まで。

出力(レスポンス) ​

field型説明
successbooltrue
modified_afterstring|null受け付けた modified_after(UTC、Y-m-d\TH:i:s\Z)。省略時は null
countintitems の件数
truncatedbool上限で打ち切ったか
itemsarray有料記事の項目。更新日時の新しい順

HTTP ステータス: 200。1 回の取得は最大 50 件(XAnnounceArticleReaderInterface::PAID_LIST_LIMIT)。超えるときは更新日時の新しい順に 50 件を返し、truncated を true にする(有料記事は月 1 本程度のため、通常は上限に達しない)。

失敗・エラー条件 ​

条件HTTPmessage
modified_after が上記の形式でない(T 区切りでタイムゾーンが無い等)・存在しない日時・オフセットが範囲外400XAnnounceRestCopy::MODIFIED_AFTER_INVALID

API-007-4 GET /paid-articles/{id} ​

入力(リクエスト) ​

param必須型・制約説明
idはい正の整数(パス)有料記事の投稿 ID

出力(レスポンス) ​

field型説明
successbooltrue
itemobject有料記事の項目

HTTP ステータス: 200

失敗・エラー条件 ​

条件HTTPmessage
id 不正400Messages::REST_INVALID_ID_MESSAGE
有料記事でない・公開済みでない・存在しない404XAnnounceRestCopy::PAID_ARTICLE_NOT_FOUND

API-007-5 POST /announcements ​

X に投稿したあとに 1 回呼ぶ。告知文の本文は受け取らない。

入力(リクエスト) ​

JSON ボディまたはフォームパラメータ。

param必須型・制約説明
post_idはい正の整数告知した記事の投稿 ID
kindはいdaily_pre / daily_after / paid_updatedaily_* は日別記事、paid_update は有料記事
tweet_idはい文字列。数字だけ 1〜20 桁X の投稿 ID。JSON の数値は精度が落ちるため文字列で送る
posted_atはいISO 8601(タイムゾーン必須、小数秒は任意。オフセットは ±14:59 まで)X に投稿した日時。UTC に直して保存する

出力(レスポンス) ​

field型説明
successbooltrue
resultstringcreated(新規に記録)/ duplicate(同じ記事の保存中の履歴に同じ tweet_id があった)
announcement.post_idint投稿 ID
announcement.kindstring告知の種類
announcement.tweet_idstringX の投稿 ID
announcement.tweet_urlstringX の投稿 URL
announcement.posted_atstring投稿日時(UTC、Y-m-d\TH:i:s\Z)

HTTP ステータス: created は 201、duplicate は 200。同じ tweet_id を再送しても履歴は増えないため、タイムアウト後の再送はそのまま行ってよい。重複の判定は保存中の最新 20 件だけが対象で、上限で消えた古い tweet_id を送り直すと created として記録し直す。

失敗・エラー条件 ​

条件HTTPmessage
post_id が正の整数でない400XAnnounceRestCopy::POST_ID_INVALID
kind が上記以外400XAnnounceRestCopy::KIND_INVALID
tweet_id が文字列でない・数字以外を含む・21 桁以上400XAnnounceRestCopy::TWEET_ID_INVALID
posted_at が ISO 8601 でない・タイムゾーンが無い・存在しない日時・オフセットが範囲外400XAnnounceRestCopy::POSTED_AT_INVALID
記事が kind の投稿タイプでない・公開済みでない・存在しない404XAnnounceRestCopy::DAILY_ARTICLE_NOT_FOUND / PAID_ARTICLE_NOT_FOUND
post meta を保存できなかった503XAnnounceRestCopy::RECORD_FAILED

監査ログ ​

BotRestAuditLogger で error_log に 1 行 JSON(接頭辞 [bot-rest-audit])を書く。記録するのはルート・ユーザー ID・post_id・kind・tweet_id・結果(outcome: created / duplicate / failed / not_found)だけ。入力検証で 400 になったリクエストは記録しない。

API-007-6 GET /settings ​

X への投稿方法を記事の種類ごとに返す。bot は告知文を作ったあと、投稿前に毎回呼ぶ。値は管理画面(ADM-036)で管理者だけが変更でき、REST に書き込みのルートは無い。

入力(リクエスト) ​

なし。

出力(レスポンス) ​

field型説明
successbooltrue
posting_modes.daily_articlestring日別記事の告知(daily_pre / daily_after)の投稿方法
posting_modes.paid_articlestring有料記事の告知(paid_update)の投稿方法

HTTP ステータス: 200。

値bot の動き
api承認後に bot が X API で投稿し、API-007-5 で告知履歴を記録する
manualX には投稿せず、告知文とアイキャッチ URL を人間に渡して終わる。人間が投稿した分の告知履歴は記録しない(API-007-5 を呼ばない)

保存先は wp_options x_announce_posting_modes(XAnnouncementConstants::OPTION_POSTING_MODES、投稿タイプ => 値の配列)。未設定・不正値は manual(API キーを用意していないまま自動投稿しないため)。

失敗・エラー条件 ​

権限・レート制限以外の失敗は無い。

権限・nonce・レート制限 ​

全エンドポイント共通。XAnnounceRestHandler + WordPressXAnnouncePermissionChecker。Handler がルートごとに action(read / record)を付け、Checker は action に応じて Capability とレート制限を変える。action が無い・不明なときは 403。

項目GET(API-007-1〜4・6)POST(API-007-5)
Capabilityread_x_announcerecord_x_announcement
レート制限ユーザー単位で 1 分あたり 120 回ユーザー単位で 1 分あたり 20 回
カウンタ不可時通す(fail-open)拒否する(fail-closed、429)
項目内容
匿名アクセス403
nonce検証しない(アプリケーションパスワード前提)。Cookie 認証で呼ぶ場合の REST nonce は WordPress コア側の挙動に従う
レート制限BotRestRateLimiter(transient、60 秒の固定ウィンドウ)。バケットは x-announce:read / x-announce:record。超過時は 429
ログログイン済みユーザーの 403 と、429 のときだけ error_log に 1 行(ステータス・user_id・ルート)。未ログインの 403 と許可したアクセスは記録しない
Local バイパスAPI-001 の WordPressPermissionChecker と同じ条件(レート制限もかけない)

X告知担当ロールは wp-admin を開けない(MemberAdminAccessGuardHooks がサイトトップへリダイレクトし、管理バーも出さない)。記事の Capability(edit_daily_articles / edit_paid_articles 等)は持たない。

WordPress コア経由の書き込みの遮断 ​

x_announcer を持ち、他には REST 用 bot ロール(ops_status_reader / birthday_linker)しか持たないユーザーには BotWriteGuardHooks(MemberServiceProvider で登録)で、運用確認bot(API-006)と同じ制限をかける。違いは REST の POST /x-announce/v1/announcements を通すこと。他の bot ロールを併せ持つ場合は、そのロールの許可ルートも合わせて通す。birthday_linker を併せ持つユーザーには、下表のエラーコードの代わりに birthday_write_forbidden / birthday_xmlrpc_forbidden(API-008)を返す。bot ロール以外のロールを併せ持つユーザーは対象外。

ログインパスワードで wp-login からブラウザにログインした場合、フロントの会員プロフィール・退会フォームやコメント投稿は止めない。そのため、X告知担当のログインパスワードは長いランダムな値にして保存・使用せず、アプリケーションパスワードだけで運用する(利用手順)。

経路フック内容
RESTrest_pre_dispatchGET / HEAD / OPTIONS と POST /x-announce/v1/announcements 以外は 403(x_announce_write_forbidden、XAnnounceRestCopy::WRITE_FORBIDDEN)。/wp/v2/users/me の更新やアプリケーションパスワードの API も含む
権限map_meta_cap自分自身に対する edit_user / create_app_password / edit_app_password / delete_app_password / delete_app_passwords を do_not_allow。管理者が bot に対して行う操作は対象外
XML-RPCauthenticate(優先度 100)XML-RPC リクエスト中は bot のログインを拒否する(x_announce_xmlrpc_forbidden)。アプリケーションパスワード認証(優先度 20)の後で判定する