WordPress REST API × X API 連携を実装してみた
導入
WordPress ブログの投稿を自動的に X (旧 Twitter) にシェアしたい。そう考える管理者は多いですが、実装方法となると選択肢が分かれます。プラグイン頼みにするか、API を直接叩くか。
今回は、WordPress REST API と X API を直結させ、ブログ更新時に自動投稿する仕組みを実際に構築してみました。その過程で見えた課題、実装パターン、そして意外な落とし穴について解説します。
結論から書きます
WordPress の REST API と X API を組み合わせることで、プラグイン不要な自動シェア機能が実装できます。ただし認証周りと API レート制限への対策が必須です。本記事では検証環境での実装フロー、トラブルシューティング、そして本番運用への注意点をまとめました。
仮説と目的
仮説
WordPress の REST API フックと X API の OAuth 2.0 認証を組み合わせれば、カスタムコード(プラグイン化)で自動シェアが実装でき、サードパーティプラグインの依存を減らせるのではないか。
目的
- 新規投稿時に自動的に X へ投稿を通知
- API 認証フローと実装パターンの確認
- レート制限・エラーハンドリングの現実的な対応法を探る
検証環境・前提条件
環境情報
- WordPress 6.4.3 (最新安定版)
- X API v2 (Elevated Access を想定)
- PHP 8.1 以上
- wp-cli 導入済み
- 検証日時: 2025年 5 月実施
前提
- X Developer Portal でのアプリ登録完了
- API キーと Bearer Token の取得済み
- WordPress のテーマまたはカスタムプラグインにコードを記述可能な環境
実装の基本フロー
WordPress REST API で投稿フックを捕捉
まず WordPress 側で、新規投稿の作成・更新時に何かアクションを起動する必要があります。REST API 経由で投稿が作られる場合、rest_insert_post フックが発火します。
// functions.php または custom-plugin.php
add_action('rest_insert_post', 'share_to_x_api', 10, 3);
function share_to_x_api($post, $request, $creating) {
// 新規作成時のみ実行
if (!$creating) {
return;
}
// 特定のカテゴリやステータスのみ対象にする
if ($post->post_status !== 'publish') {
return;
}
// X API へ通知を送る
send_to_x($post);
}
ここで重要なのは、REST API 経由での作成のみ を想定していることです。WordPress の管理画面から投稿した場合は、このフックが発火しません(その場合は publish_post などの別フックを使う必要があります)。
X API への投稿送信
次に、X API v2 の POST /tweets エンドポイントを叩きます。認証は Bearer Token を使う方式です。
function send_to_x($post) {
$post_title = $post->post_title;
$post_url = get_permalink($post->ID);
// X に投稿するテキスト(280字以内)
$tweet_text = sprintf(
"📝 新しい記事を公開しました\n\n%s\n\n%s",
$post_title,
$post_url
);
// 280字超過チェック
if (mb_strlen($tweet_text) > 280) {
$tweet_text = mb_substr($post_title, 0, 50) . "...\n\n" . $post_url;
}
$x_api_url = 'https://api.twitter.com/2/tweets';
$bearer_token = get_option('x_api_bearer_token'); // 環境変数から取得推奨
$response = wp_remote_post($x_api_url, [
'headers' => [
'Authorization' => 'Bearer ' . $bearer_token,
'Content-Type' => 'application/json',
],
'body' => wp_json_encode([
'text' => $tweet_text,
]),
'timeout' => 10,
]);
if (is_wp_error($response)) {
error_log('X API Error: ' . $response->get_error_message());
return false;
}
$status_code = wp_remote_retrieve_response_code($response);
if ($status_code !== 201) {
$body = wp_remote_retrieve_body($response);
error_log('X API returned ' . $status_code . ': ' . $body);
return false;
}
return true;
}
チェックポイント
- Bearer Token は環境変数またはセキュアなオプションテーブルに保管
wp_remote_post()で HTTP リクエストを送信(curl よりも WordPress 標準)- レスポンスコード 201 で成功判定
認証トークンの管理
Bearer Token を直接コードに埋め込むのは危険です。以下の方法を推奨します。
方法 1: .env ファイル(WP-CLI や Composer 環境で推奨)
X_API_BEARER_TOKEN=AAAABNRjWwEBBA...
functions.php で読み込み:
if (file_exists(__DIR__ . '/.env')) {
$env_vars = parse_ini_file(__DIR__ . '/.env');
define('X_API_BEARER_TOKEN', $env_vars['X_API_BEARER_TOKEN'] ?? '');
}
方法 2: wp-config.php に定義
define('X_API_BEARER_TOKEN', getenv('X_API_BEARER_TOKEN'));
方法 3: WordPress オプションテーブル(管理画面から変更可能)
update_option('x_api_bearer_token', 'AAAA...', false);
$token = get_option('x_api_bearer_token');
方法 3 はセキュリティリスクがあるため、本番環境では環境変数推奨です。
レート制限への対応
X API v2 には レート制限があります。通常、1 ユーザー当たり 15 分間に 300 リクエストです。ブログ 1 つ程度なら問題になりませんが、複数ドメインを運用する場合は工夫が必要です。
キューイングシステムの導入
投稿を即座に X へ送らず、一度 WordPress のメタデータに保存し、別タスクで処理する方法があります。
add_action('rest_insert_post', 'queue_x_share', 10, 3);
function queue_x_share($post, $request, $creating) {
if (!$creating || $post->post_status !== 'publish') {
return;
}
// メタデータに保存(まだ送信していない状態)
update_post_meta($post->ID, 'x_share_pending', true);
update_post_meta($post->ID, 'x_share_timestamp', current_time('timestamp'));
}
// 定期実行(WP-Cron または 外部 cron)
add_action('wp_scheduled_x_share', 'process_x_share_queue');
function process_x_share_queue() {
$pending_posts = get_posts([
'meta_key' => 'x_share_pending',
'meta_value' => true,
'numberposts' => 5, // 1 回の処理で 5 件まで
]);
foreach ($pending_posts as $post) {
if (send_to_x($post)) {
delete_post_meta($post->ID, 'x_share_pending');
update_post_meta($post->ID, 'x_share_sent', true);
}
}
}
// 15 分ごとに実行
if (!wp_next_scheduled('wp_scheduled_x_share')) {
wp_schedule_event(time(), '15min', 'wp_scheduled_x_share');
}
この方式により、API レート制限に巻き込まれるリスクが低減します。
トラブルシューティング
エラー: 401 Unauthorized
原因
- Bearer Token が空または不正
- Token の有効期限切れ(OAuth 2.0 の場合)
対応
if ($status_code === 401) {
error_log('X API: 認証トークン無効。トークンを再取得してください。');
// 管理者メール通知
wp_mail(get_option('admin_email'), 'X API 認証エラー', 'トークン更新が必要です。');
}
エラー: 429 Too Many Requests
原因
レート制限に達した。
対応
if ($status_code === 429) {
// メタデータを再度セット(後で再試行)
update_post_meta($post->ID, 'x_share_retry_count',
(int)get_post_meta($post->ID, 'x_share_retry_count', true) + 1);
// 3 回までリトライ
$retry_count = (int)get_post_meta($post->ID, 'x_share_retry_count', true);
if ($retry_count < 3) {
update_post_meta($post->ID, 'x_share_pending', true);
}
}
エラー: 422 Unprocessable Entity
原因
POST データの形式が不正。よくは 280 字超過。
対応
テキストの事前検証を強化:
function validate_tweet_text($text) {
$text = trim($text);
// 絵文字を含む場合の正確な文字数カウント
$length = mb_strlen($text);
if ($length > 280) {
return false; // または自動短縮
}
return true;
}
本番運用への注意点
セキュリティ
- Bearer Token は環境変数で管理し、ソースコードに含めない
- WordPress のユーザー権限で
publish_postsが必要な場合、REST API エンドポイント保護を強化 - X API アプリの権限を「Read and Write」に限定(「Read and Delete」は不要)
モニタリング
エラーログを定期確認するか、Slack / メール通知を組み込む:
function notify_x_share_failure($post_id, $error_message) {
$post = get_post($post_id);
$message = sprintf(
"X API 投稿失敗\nタイトル: %s\nエラー: %s\nURL: %s",
$post->post_title,
$error_message,
get_edit_post_link($post_id)
);
wp_mail(get_option('admin_email'), 'X API シェア失敗通知', $message);
}
投稿の選別
すべての投稿を X へシェアするのではなく、カテゴリやタグで絞る:
function should_share_to_x($post) {
$categories = wp_get_post_categories($post->ID);
$category_ids = wp_list_pluck(get_categories(['fields' => 'ids']), 'cat_ID');
// 「お知らせ」カテゴリのみシェア
return in_array($post->post_category[0], $category_ids);
}
考察:プラグイン vs カスタムコード
この検証を通じて、API 連携をカスタムコードで実装する利点と課題が明確になりました。
メリット
- 細かいロジック制御が可能
- 不要な機能(管理画面 UI など)が不要
- バージョン更新時の互換性不安がない
デメリット
- コードの保守責任が自分たちにある
- セキュリティ検証は自分たちで行う必要がある
- デバッグ時のログ確認が重要
結論として、運用規模が小さい場合(1-2 ドメイン)はカスタムコード、複数運用ならプラグイン化を検討 する方針が現実的です。
API レート制限とキューイングの実装詳細
レート制限の対応はブログ規模によって戦略が変わります。以下、3 つのパターンを整理しました。
| パターン | 想定規模 | キューイング | リトライ |
|---|---|---|---|
| 直送 | 月 1-5 投稿 | 不要 | シンプル |
| キュー + 定期実行 | 月 6-30 投稿 | 推奨 | 3 回 |
| 外部キュー(SQS など) | 月 30+ 投稿 | 必須 | カスタマイズ可 |
月 30 投稿程度なら、前述のキューイング方式(15 分ごと)で十分対応できます。
カスタムプラグイン化への最終手順
ここまでのコードを整理し、プラグイン化する手順を示します。
ファイル構成
wp-content/plugins/x-api-auto-share/
├── x-api-auto-share.php (メインプラグインファイル)
├── includes/
│ ├── class-x-api.php
│ ├── class-queue-manager.php
│ └── hooks.php
├── readme.txt
└── .gitignore
x-api-auto-share.php (メイン)
<?php
/**
* Plugin Name: X API Auto Share
* Description: REST API で投稿作成時に自動的に X へシェア
* Version: 1.0.0
* Author: Your Name
* License: GPL v2
*/
if (!defined('ABSPATH')) exit;
define('X_API_SHARE_PATH', plugin_dir_path(__FILE__));
require_once X_API_SHARE_PATH . 'includes/class-x-api.php';
require_once X_API_SHARE_PATH . 'includes/class-queue-manager.php';
require_once X_API_SHARE_PATH . 'includes/hooks.php';
register_activation_hook(__FILE__, function() {
// 定期タスク登録
if (!wp_next_scheduled('wp_scheduled_x_share')) {
wp_schedule_event(time(), '15min', 'wp_scheduled_x_share');
}
});
register_deactivation_hook(__FILE__, function() {
wp_clear_scheduled_hook('wp_scheduled_x_share');
});
includes/class-x-api.php
<?php
class X_API {
private $bearer_token;
private $api_url = 'https://api.twitter.com/2/tweets';
public function __construct() {
$this->bearer_token = getenv('X_API_BEARER_TOKEN')
?: get_option('x_api_bearer_token');
}
public function post_tweet($text) {
if (mb_strlen($text) > 280) {
return new WP_Error('text_too_long', 'Tweet text exceeds 280 characters.');
}
$response = wp_remote_post($this->api_url, [
'headers' => [
'Authorization' => 'Bearer ' . $this->bearer_token,
'Content-Type' => 'application/json',
],
'body' => wp_json_encode(['text' => $text]),
'timeout' => 10,
]);
if (is_wp_error($response)) {
return $response;
}
$status_code = wp_remote_retrieve_response_code($response);
if ($status_code === 201) {
return true;
}
$body = json_decode(wp_remote_retrieve_body($response), true);
return new WP_Error('x_api_error',
'X API error: ' . wp_json_encode($body));
}
}
includes/hooks.php
<?php
add_action('rest_insert_post', function($post, $request, $creating) {
if (!$creating || $post->post_status !== 'publish') {
return;
}
update_post_meta($post->ID, 'x_share_pending', true);
update_post_meta($post->ID, 'x_share_timestamp', current_time('timestamp'));
}, 10, 3);
add_action('wp_scheduled_x_share', function() {
$x_api = new X_API();
$queue_mgr = new Queue_Manager();
$queue_mgr->process($x_api);
});
このプラグイン化により、複数プロジェクトでの再利用や、GitHub での管理が可能になります。
※本記事は2026-05-16時点の情報に基づきます。AI モデルや API の仕様・料金は変更されることがあります。最新は公式ドキュメントをご確認ください。
AI / tech の選択は要件や環境によって最適解が変わります。本記事は参考情報で、最終的な技術判断はご自身の検証に基づいてください。
まとめ
- REST API フックと X API Bearer Token で直結可能 — プラグイン不要な実装ができる
- レート制限対策としてキューイング + 定期実行が現実的 — 月 30 投稿程度までカバー可能
- 本番運用ではトークン管理・エラーハンドリング・モニタリングが必須 — セキュリティと安定性のため
次の段階としては、複数の X アカウント運用への対応、または Bluesky API への同時投稿を試してみたい。
Photo by 1981 Digital on Unsplash