{"id":231,"date":"2026-05-21T08:00:22","date_gmt":"2026-05-20T23:00:22","guid":{"rendered":"https:\/\/shimaken.com\/schnauzer\/231\/"},"modified":"2026-05-21T08:00:22","modified_gmt":"2026-05-20T23:00:22","slug":"wordpress-rest-api-x-api-2","status":"publish","type":"post","link":"https:\/\/shimaken.com\/schnauzer\/231\/","title":{"rendered":"WordPress REST API \u3068 X API \u3092\u9023\u643a\u3055\u305b\u305f\u81ea\u52d5\u6295\u7a3f\u3092\u8a66\u3057\u305f\u8a18\u9332"},"content":{"rendered":"<h1>WordPress REST API \u3068 X API \u3092\u9023\u643a\u3055\u305b\u305f\u81ea\u52d5\u6295\u7a3f\u3092\u8a66\u3057\u305f\u8a18\u9332<\/h1>\n<p>WordPress\u3067\u8a18\u4e8b\u3092\u516c\u958b\u3059\u308b\u305f\u3073\u306b\u3001\u624b\u3067X\u306b\u6295\u7a3f\u30ea\u30f3\u30af\u3092\u8cbc\u308a\u4ed8\u3051\u3066\u3044\u308b\u3002\u3053\u306e\u4f5c\u696d\u3001\u6708\u306b20\u301c30\u672c\u306e\u8a18\u4e8b\u3092\u904b\u7528\u3059\u308b\u3088\u3046\u306b\u306a\u308b\u3068\u3001\u3058\u308f\u3058\u308f\u3068\u6642\u9593\u3092\u98df\u3046\u3002<\/p>\n<p>\u300cAPI\u3067\u81ea\u52d5\u5316\u3067\u304d\u308b\u306f\u305a\u300d\u3068\u8003\u3048\u308b\u4eba\u306f\u591a\u3044\u304c\u3001\u3044\u3056\u624b\u3092\u52d5\u304b\u3059\u3068\u6700\u521d\u306e\u8a8d\u8a3c\u307e\u308f\u308a\u3067\u3064\u307e\u305a\u3044\u3066\u653e\u7f6e\u3001\u3068\u3044\u3046\u30d1\u30bf\u30fc\u30f3\u3092\u3088\u304f\u805e\u304f\u3002WordPress REST API\u306e\u8a8d\u8a3c\u65b9\u5f0f\u3068X API(\u65e7Twitter API) v2\u306e\u8a8d\u8a3c\u65b9\u5f0f\u304c\u5225\u7269\u3067\u3042\u308b\u3053\u3068\u304c\u7406\u89e3\u3055\u308c\u3066\u3044\u306a\u3044\u307e\u307e\u5b9f\u88c5\u3092\u59cb\u3081\u308b\u3068\u3001401\u30a8\u30e9\u30fc\u3067\u6b62\u307e\u308b\u3002<\/p>\n<p>\u3053\u306e\u8a18\u4e8b\u3067\u306f\u3001WordPress\u306e\u8a18\u4e8b\u516c\u958b\u3092\u30c8\u30ea\u30ac\u30fc\u306b\u3001X(\u65e7Twitter)\u3078\u81ea\u52d5\u6295\u7a3f\u3059\u308bPython\u30b9\u30af\u30ea\u30d7\u30c8\u3092\u5b9f\u969b\u306b\u52d5\u304b\u3057\u305f\u624b\u9806\u3092\u8a18\u9332\u3059\u308b\u3002\u524d\u63d0\u77e5\u8b58\u306fPython\u306e\u57fa\u790e\u3068\u3001WordPress\u3092\u81ea\u5206\u3067\u904b\u7528\u3057\u305f\u7d4c\u9a13\u304c\u3042\u308c\u3070\u5341\u5206\u3060\u3002<\/p>\n<h2>\u7d50\u8ad6\u304b\u3089\u66f8\u304d\u307e\u3059<\/h2>\n<p>WordPress REST API\u3067\u300c\u516c\u958b\u6e08\u307f\u8a18\u4e8b\u306e\u4e00\u89a7\u300d\u3092\u53d6\u5f97\u3057\u3001X\u306b\u6295\u7a3f\u3057\u3066\u3044\u306a\u3044\u3082\u306e\u3092Python\u30b9\u30af\u30ea\u30d7\u30c8\u304c\u691c\u77e5\u3057\u3066\u30c4\u30a4\u30fc\u30c8\u3059\u308b\u3001\u3068\u3044\u3046\u69cb\u6210\u304c\u6700\u3082\u30b7\u30f3\u30d7\u30eb\u306b\u52d5\u304f\u3002<\/p>\n<p>\u8a8d\u8a3c\u306f2\u7a2e\u985e\u306b\u5206\u3051\u3066\u7ba1\u7406\u3059\u308b\u3002WordPress\u5074\u306fApplication Passwords\u3067\u5bfe\u5fdc\u3057\u3001X\u5074\u306fOAuth 1.0a(Consumer Key + Access Token)\u3067\u5bfe\u5fdc\u3059\u308b\u3002\u3069\u3061\u3089\u3082\u516c\u5f0f\u306e\u63a8\u5968\u624b\u9806\u306b\u5f93\u3048\u3070\u3001\u30b3\u30fc\u30c9\u305d\u306e\u3082\u306e\u306f\u30b7\u30f3\u30d7\u30eb\u306b\u66f8\u3051\u308b\u3002<\/p>\n<h2>\u691c\u8a3c\u74b0\u5883\u3068\u524d\u63d0\u6761\u4ef6<\/h2>\n<table>\n<thead>\n<tr>\n<th>\u9805\u76ee<\/th>\n<th>\u30d0\u30fc\u30b8\u30e7\u30f3 \/ \u5024<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Python<\/td>\n<td>3.11.9<\/td>\n<\/tr>\n<tr>\n<td>WordPress<\/td>\n<td>6.5.3<\/td>\n<\/tr>\n<tr>\n<td>WordPress REST API<\/td>\n<td>v2 (\u30b3\u30a2\u540c\u68b1)<\/td>\n<\/tr>\n<tr>\n<td>X API<\/td>\n<td>v2 (Free tier)<\/td>\n<\/tr>\n<tr>\n<td>\u4e3b\u306a\u30e9\u30a4\u30d6\u30e9\u30ea<\/td>\n<td><code>requests<\/code> 2.32\u3001<code>tweepy<\/code> 4.14<\/td>\n<\/tr>\n<tr>\n<td>\u691c\u8a3c\u65e5<\/td>\n<td>2026-05-21<\/td>\n<\/tr>\n<tr>\n<td>\u5b9f\u884c\u74b0\u5883<\/td>\n<td>Ubuntu 22.04 LTS (VPS)<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>X API \u306eFree tier\u306f\u3001\u6708\u9593\u30c4\u30a4\u30fc\u30c8\u6295\u7a3f\u6570\u306b\u4e0a\u9650\u304c\u3042\u308b(2024\u5e74\u6642\u70b9\u3067\u306f\u6708500\u30c4\u30a4\u30fc\u30c8\u307e\u3067)\u3002\u8a18\u4e8b\u306e\u81ea\u52d5\u6295\u7a3f\u7a0b\u5ea6\u3067\u3042\u308c\u3070\u554f\u984c\u306a\u3044\u304c\u3001\u5927\u91cf\u6295\u7a3f\u306b\u306f\u6709\u6599\u30d7\u30e9\u30f3\u304c\u5fc5\u8981\u306b\u306a\u308b(\u51fa\u5178: X Developer Platform \u516c\u5f0f\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8)\u3002<\/p>\n<p>WordPress\u306eApplication Passwords\u306f\u3001WordPress 5.6\u4ee5\u964d\u3067\u6a19\u6e96\u642d\u8f09\u3055\u308c\u3066\u3044\u308b\u6a5f\u80fd\u3060\u3002\u30e6\u30fc\u30b6\u30fc\u306e\u300c\u30d7\u30ed\u30d5\u30a3\u30fc\u30eb\u300d\u30da\u30fc\u30b8\u304b\u3089\u767a\u884c\u3067\u304d\u3001\u901a\u5e38\u306e\u30ed\u30b0\u30a4\u30f3\u30d1\u30b9\u30ef\u30fc\u30c9\u3068\u306f\u5225\u306b\u7ba1\u7406\u3067\u304d\u308b\u3002<\/p>\n<hr>\n<p>\u8a8d\u8a3c\u60c5\u5831\u306e\u6271\u3044\u306b\u3064\u3044\u3066\u88dc\u8db3\u3057\u3066\u304a\u304f\u3002\u3059\u3079\u3066\u306e\u8a8d\u8a3c\u60c5\u5831(API\u30ad\u30fc\u3001\u30a2\u30af\u30bb\u30b9\u30c8\u30fc\u30af\u30f3\u3001WordPress\u306eApplication Password)\u306f\u3001\u30b9\u30af\u30ea\u30d7\u30c8\u672c\u4f53\u306b\u306f\u4e00\u5207\u66f8\u304b\u306a\u3044\u3002<code>.env<\/code>\u30d5\u30a1\u30a4\u30eb\u306b\u683c\u7d0d\u3057\u3001<code>python-dotenv<\/code>\u3067\u8aad\u307f\u8fbc\u3080\u65b9\u5f0f\u3092\u4f7f\u3046\u3002<code>.env<\/code>\u306fGit\u306e\u7ba1\u7406\u5bfe\u8c61\u304b\u3089\u5916\u3059(<code>.gitignore<\/code>\u306b\u8ffd\u8a18)\u3002<\/p>\n<h2>WordPress REST API\u3067\u8a18\u4e8b\u30c7\u30fc\u30bf\u3092\u53d6\u5f97\u3059\u308b<\/h2>\n<h3>\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8\u306e\u57fa\u672c\u69cb\u9020<\/h3>\n<p>WordPress REST API\u306e\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8\u306f\u6b21\u306e\u5f62\u5f0f\u3067\u69cb\u6210\u3055\u308c\u308b\u3002<\/p>\n<pre><code>https:\/\/your-site.com\/wp-json\/wp\/v2\/posts\n<\/code><\/pre>\n<p>\u8a8d\u8a3c\u306a\u3057\u3067\u3082\u30a2\u30af\u30bb\u30b9\u3067\u304d\u308b\u304c\u3001\u4e0b\u66f8\u304d\u3084\u975e\u516c\u958b\u8a18\u4e8b\u3092\u53d6\u5f97\u3057\u305f\u3044\u5834\u5408\u306fApplication Passwords\u306b\u3088\u308b\u8a8d\u8a3c\u304c\u5fc5\u8981\u306b\u306a\u308b\u3002\u4eca\u56de\u306f\u300c\u516c\u958b\u6e08\u307f\u8a18\u4e8b\u306e\u53d6\u5f97\u300d\u304c\u76ee\u7684\u306a\u306e\u3067\u3001\u8a8d\u8a3c\u306f\u5fc5\u9808\u3067\u306f\u306a\u3044\u3002\u305f\u3060\u3057\u5f8c\u5de5\u7a0b\u3067X\u672a\u6295\u7a3f\u304b\u3069\u3046\u304b\u3092\u7ba1\u7406\u3059\u308b\u305f\u3081\u306b\u3001\u6295\u7a3f\u6e08\u307f\u306epost_id\u3092\u30ed\u30fc\u30ab\u30eb\u30d5\u30a1\u30a4\u30eb\u306b\u8a18\u9332\u3059\u308b\u4ed5\u7d44\u307f\u3092\u5165\u308c\u308b\u3002<\/p>\n<h3>\u5b9f\u88c5\u30b3\u30fc\u30c9<\/h3>\n<p>\u307e\u305a<code>.env<\/code>\u30d5\u30a1\u30a4\u30eb\u3092\u7528\u610f\u3059\u308b\u3002<\/p>\n<pre><code>WP_BASE_URL=https:\/\/your-site.com\nX_CONSUMER_KEY=your_consumer_key\nX_CONSUMER_SECRET=your_consumer_secret\nX_ACCESS_TOKEN=your_access_token\nX_ACCESS_TOKEN_SECRET=your_access_token_secret\n<\/code><\/pre>\n<p>\u6b21\u306b\u3001WordPress\u306e\u8a18\u4e8b\u4e00\u89a7\u3092\u53d6\u5f97\u3059\u308b\u30b3\u30fc\u30c9\u3092\u66f8\u304f\u3002<\/p>\n<pre><code class=\"language-python\">import os\nimport json\nimport requests\nfrom dotenv import load_dotenv\n\nload_dotenv()\n\nWP_BASE_URL = os.getenv(&quot;WP_BASE_URL&quot;)\n\ndef get_recent_posts(per_page: int = 10) -&gt; list[dict]:\n    &quot;&quot;&quot;\u516c\u958b\u6e08\u307f\u8a18\u4e8b\u3092\u65b0\u3057\u3044\u9806\u306b\u53d6\u5f97\u3059\u308b&quot;&quot;&quot;\n    url = f&quot;{WP_BASE_URL}\/wp-json\/wp\/v2\/posts&quot;\n    params = {\n        &quot;status&quot;: &quot;publish&quot;,\n        &quot;per_page&quot;: per_page,\n        &quot;orderby&quot;: &quot;date&quot;,\n        &quot;order&quot;: &quot;desc&quot;,\n        &quot;_fields&quot;: &quot;id,title,link,date&quot;  # \u5fc5\u8981\u30d5\u30a3\u30fc\u30eb\u30c9\u306e\u307f\u53d6\u5f97\n    }\n    response = requests.get(url, params=params, timeout=10)\n    response.raise_for_status()\n    return response.json()\n<\/code><\/pre>\n<p><code>_fields<\/code>\u30d1\u30e9\u30e1\u30fc\u30bf\u3067\u53d6\u5f97\u30d5\u30a3\u30fc\u30eb\u30c9\u3092\u7d5e\u308b\u3053\u3068\u3067\u3001\u30ec\u30b9\u30dd\u30f3\u30b9\u306e\u30b5\u30a4\u30ba\u3092\u5c0f\u3055\u304f\u3067\u304d\u308b\u3002\u5168\u30d5\u30a3\u30fc\u30eb\u30c9\u3092\u53d6\u5f97\u3059\u308b\u3068content\u3084excerpt\u304c\u542b\u307e\u308c\u3001\u8a18\u4e8b\u672c\u6587\u307e\u3067\u6d41\u308c\u3066\u304f\u308b\u3002\u4e0d\u8981\u306a\u30c7\u30fc\u30bf\u3092\u53d6\u3089\u306a\u3044\u7fd2\u6163\u306f\u3001\u7279\u306bAPI\u547c\u3073\u51fa\u3057\u983b\u5ea6\u304c\u4e0a\u304c\u3063\u305f\u3068\u304d\u306b\u52b9\u3044\u3066\u304f\u308b\u3002<\/p>\n<h3>\u672a\u6295\u7a3f\u8a18\u4e8b\u306e\u691c\u51fa\u30ed\u30b8\u30c3\u30af<\/h3>\n<p>\u6295\u7a3f\u6e08\u307f\u306epost_id\u3092JSON\u30d5\u30a1\u30a4\u30eb\u306b\u4fdd\u5b58\u3057\u3066\u304a\u304d\u3001\u5dee\u5206\u3092\u53d6\u308b\u3002<\/p>\n<pre><code class=\"language-python\">POSTED_IDS_FILE = &quot;posted_ids.json&quot;\n\ndef load_posted_ids() -&gt; set[int]:\n    &quot;&quot;&quot;\u6295\u7a3f\u6e08\u307fID\u3092\u30bb\u30c3\u30c8\u3068\u3057\u3066\u8aad\u307f\u8fbc\u3080&quot;&quot;&quot;\n    if not os.path.exists(POSTED_IDS_FILE):\n        return set()\n    with open(POSTED_IDS_FILE, &quot;r&quot;) as f:\n        return set(json.load(f))\n\ndef save_posted_id(post_id: int) -&gt; None:\n    &quot;&quot;&quot;\u6295\u7a3f\u6e08\u307fID\u3092\u8ffd\u8a18\u4fdd\u5b58\u3059\u308b&quot;&quot;&quot;\n    ids = load_posted_ids()\n    ids.add(post_id)\n    with open(POSTED_IDS_FILE, &quot;w&quot;) as f:\n        json.dump(list(ids), f)\n\ndef find_new_posts(posts: list[dict]) -&gt; list[dict]:\n    &quot;&quot;&quot;\u672a\u6295\u7a3f\u306e\u8a18\u4e8b\u3060\u3051\u3092\u8fd4\u3059&quot;&quot;&quot;\n    posted_ids = load_posted_ids()\n    return [p for p in posts if p[&quot;id&quot;] not in posted_ids]\n<\/code><\/pre>\n<p>DB\u3092\u4f7f\u308f\u305aJSON\u30d5\u30a1\u30a4\u30eb\u3067\u7ba1\u7406\u3059\u308b\u306e\u306f\u3001\u30b7\u30f3\u30d7\u30eb\u3055\u3092\u512a\u5148\u3057\u305f\u9078\u629e\u3060\u3002\u8a18\u4e8b\u672c\u6570\u304c\u6570\u5343\u672c\u3092\u8d85\u3048\u308b\u3088\u3046\u306a\u30e1\u30c7\u30a3\u30a2\u3067\u306f\u3001SQLite\u3084Redis\u306b\u5207\u308a\u66ff\u3048\u308b\u65b9\u304c\u5b89\u5b9a\u3059\u308b\u3002\u670830\u672c\u7a0b\u5ea6\u3067\u3042\u308c\u3070\u3001JSON\u30d5\u30a1\u30a4\u30eb\u3067\u5341\u5206\u306b\u6a5f\u80fd\u3059\u308b\u3002<\/p>\n<h2>X API v2 \u3067\u81ea\u52d5\u30c4\u30a4\u30fc\u30c8\u3092\u9001\u4fe1\u3059\u308b<\/h2>\n<h3>\u8a8d\u8a3c\u306e\u4ed5\u7d44\u307f\u3068tweepy\u306e\u4f7f\u3044\u65b9<\/h3>\n<p>X API v2\u3067\u30c4\u30a4\u30fc\u30c8\u3092\u6295\u7a3f\u3059\u308b\u306b\u306f\u3001OAuth 1.0a\u8a8d\u8a3c\u304c\u5fc5\u8981\u3060\u30024\u3064\u306e\u30ad\u30fc\u3092\u4f7f\u3046\u3002<\/p>\n<ul>\n<li>Consumer Key(API Key)<\/li>\n<li>Consumer Secret(API Key Secret)<\/li>\n<li>Access Token<\/li>\n<li>Access Token Secret<\/li>\n<\/ul>\n<p>\u3053\u308c\u3089\u306fX Developer Portal(developer.twitter.com)\u306e\u30a2\u30d7\u30ea\u8a2d\u5b9a\u753b\u9762\u304b\u3089\u767a\u884c\u3067\u304d\u308b\u3002Free tier\u3067\u3082\u30a2\u30d7\u30ea\u3092\u4f5c\u6210\u3057\u3001Read and Write\u306e\u30d1\u30fc\u30df\u30c3\u30b7\u30e7\u30f3\u3092\u8a2d\u5b9a\u3059\u308c\u3070\u53d6\u5f97\u3067\u304d\u308b(\u51fa\u5178: X Developer Platform \u2014 Getting Access to the X API)\u3002<\/p>\n<p><code>tweepy<\/code>\u30e9\u30a4\u30d6\u30e9\u30ea\u3092\u4f7f\u3046\u3068\u3001\u8a8d\u8a3c\u307e\u308f\u308a\u306e\u30b3\u30fc\u30c9\u304c\u5927\u5e45\u306b\u30b7\u30f3\u30d7\u30eb\u306b\u306a\u308b\u3002<\/p>\n<pre><code class=\"language-python\">import tweepy\n\ndef get_x_client() -&gt; tweepy.Client:\n    &quot;&quot;&quot;tweepy \u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u3092\u751f\u6210\u3057\u3066\u8fd4\u3059&quot;&quot;&quot;\n    return tweepy.Client(\n        consumer_key=os.getenv(&quot;X_CONSUMER_KEY&quot;),\n        consumer_secret=os.getenv(&quot;X_CONSUMER_SECRET&quot;),\n        access_token=os.getenv(&quot;X_ACCESS_TOKEN&quot;),\n        access_token_secret=os.getenv(&quot;X_ACCESS_TOKEN_SECRET&quot;),\n    )\n<\/code><\/pre>\n<h3>\u30c4\u30a4\u30fc\u30c8\u30c6\u30ad\u30b9\u30c8\u306e\u7d44\u307f\u7acb\u3066<\/h3>\n<p>\u8a18\u4e8b\u30bf\u30a4\u30c8\u30eb\u3068URL\u3092\u7d44\u307f\u5408\u308f\u305b\u3066\u30c4\u30a4\u30fc\u30c8\u672c\u6587\u3092\u4f5c\u308b\u3002X\u306e\u30c4\u30a4\u30fc\u30c8\u6587\u5b57\u6570\u4e0a\u9650\u306f280\u6587\u5b57(\u65e5\u672c\u8a9e\u3067\u3082\u540c\u3058)\u3060\u304c\u3001URL\u306f\u77ed\u7e2eURL\u306b\u5909\u63db\u3055\u308c\u306623\u6587\u5b57\u3068\u3057\u3066\u30ab\u30a6\u30f3\u30c8\u3055\u308c\u308b\u4ed5\u69d8\u3060(\u51fa\u5178: X Help Center \u2014 About Twitter&#8217;s character limit)\u3002<\/p>\n<pre><code class=\"language-python\">def build_tweet_text(post: dict) -&gt; str:\n    &quot;&quot;&quot;\u30c4\u30a4\u30fc\u30c8\u672c\u6587\u3092\u7d44\u307f\u7acb\u3066\u308b&quot;&quot;&quot;\n    title = post[&quot;title&quot;][&quot;rendered&quot;]\n    url = post[&quot;link&quot;]\n    # \u30bf\u30a4\u30c8\u30eb\u304c\u9577\u3044\u5834\u5408\u306f\u5207\u308a\u8a70\u3081\u308b\n    max_title_len = 100\n    if len(title) &gt; max_title_len:\n        title = title[:max_title_len] + &quot;\u2026&quot;\n    return f&quot;{title}\\n\\n{url}&quot;\n\ndef post_tweet(client: tweepy.Client, text: str) -&gt; bool:\n    &quot;&quot;&quot;\u30c4\u30a4\u30fc\u30c8\u3092\u9001\u4fe1\u3059\u308b\u3002\u6210\u529f\u3067True\u3001\u5931\u6557\u3067False\u3092\u8fd4\u3059&quot;&quot;&quot;\n    try:\n        response = client.create_tweet(text=text)\n        return response.data is not None\n    except tweepy.TweepyException as e:\n        print(f&quot;\u30c4\u30a4\u30fc\u30c8\u5931\u6557: {e}&quot;)\n        return False\n<\/code><\/pre>\n<p>\u30a8\u30e9\u30fc\u30cf\u30f3\u30c9\u30ea\u30f3\u30b0\u306f\u6700\u4f4e\u9650\u306e\u5f62\u3067\u5165\u308c\u3066\u3044\u308b\u3002\u672c\u756a\u904b\u7528\u306b\u79fb\u3059\u5834\u5408\u306f\u3001\u30ed\u30b0\u30d5\u30a1\u30a4\u30eb\u3078\u306e\u66f8\u304d\u8fbc\u307f\u3084\u3001\u5931\u6557\u6642\u306e\u30ea\u30c8\u30e9\u30a4\u56de\u6570\u306e\u4e0a\u9650\u8a2d\u5b9a\u3092\u8ffd\u52a0\u3059\u308b\u3053\u3068\u3092\u60f3\u5b9a\u3057\u3066\u3044\u308b\u3002<\/p>\n<h2>\u30e1\u30a4\u30f3\u30b9\u30af\u30ea\u30d7\u30c8\u306e\u7d71\u5408\u3068\u52d5\u4f5c\u78ba\u8a8d<\/h2>\n<h3>\u5168\u4f53\u306e\u51e6\u7406\u30d5\u30ed\u30fc<\/h3>\n<pre><code class=\"language-mermaid\">flowchart TD\n    A[\u30b9\u30af\u30ea\u30d7\u30c8\u8d77\u52d5] --&gt; B[WordPress REST API \u3067\u8a18\u4e8b\u53d6\u5f97]\n    B --&gt; C{\u672a\u6295\u7a3f\u8a18\u4e8b\u3042\u308a?}\n    C -- Yes --&gt; D[\u30c4\u30a4\u30fc\u30c8\u672c\u6587\u3092\u7d44\u307f\u7acb\u3066]\n    D --&gt; E[X API \u3067\u30c4\u30a4\u30fc\u30c8\u9001\u4fe1]\n    E --&gt; F{\u9001\u4fe1\u6210\u529f?}\n    F -- Yes --&gt; G[posted_ids.json \u306b ID \u4fdd\u5b58]\n    F -- No --&gt; H[\u30a8\u30e9\u30fc\u30ed\u30b0\u51fa\u529b]\n    G --&gt; I[\u6b21\u306e\u672a\u6295\u7a3f\u8a18\u4e8b\u3078]\n    I --&gt; C\n    C -- No --&gt; J[\u7d42\u4e86]\n<\/code><\/pre>\n<h3>\u30e1\u30a4\u30f3\u51e6\u7406<\/h3>\n<pre><code class=\"language-python\">import time\n\ndef main():\n    print(&quot;WordPress \u2192 X \u81ea\u52d5\u6295\u7a3f\u30b9\u30af\u30ea\u30d7\u30c8\u8d77\u52d5&quot;)\n\n    # WordPress \u304b\u3089\u8a18\u4e8b\u53d6\u5f97\n    posts = get_recent_posts(per_page=10)\n    new_posts = find_new_posts(posts)\n\n    if not new_posts:\n        print(&quot;\u672a\u6295\u7a3f\u306e\u8a18\u4e8b\u306f\u3042\u308a\u307e\u305b\u3093&quot;)\n        return\n\n    print(f&quot;\u672a\u6295\u7a3f\u8a18\u4e8b: {len(new_posts)} \u4ef6&quot;)\n\n    client = get_x_client()\n\n    for post in new_posts:\n        tweet_text = build_tweet_text(post)\n        success = post_tweet(client, tweet_text)\n\n        if success:\n            save_posted_id(post[&quot;id&quot;])\n            print(f&quot;\u6295\u7a3f\u5b8c\u4e86: {post['title']['rendered']}&quot;)\n            # \u30ec\u30fc\u30c8\u5236\u9650\u3078\u306e\u914d\u616e: \u6295\u7a3f\u9593\u9694\u3092\u7a7a\u3051\u308b\n            time.sleep(5)\n        else:\n            print(f&quot;\u6295\u7a3f\u5931\u6557: {post['title']['rendered']}&quot;)\n\n    print(&quot;\u51e6\u7406\u5b8c\u4e86&quot;)\n\nif __name__ == &quot;__main__&quot;:\n    main()\n<\/code><\/pre>\n<h3>\u52d5\u4f5c\u78ba\u8a8d\u6642\u306e\u624b\u9806<\/h3>\n<p>\u5b9f\u969b\u306b\u52d5\u304b\u3059\u524d\u306b\u3001\u78ba\u8a8d\u3057\u3066\u304a\u304f\u3079\u304d\u70b9\u304c\u3042\u308b\u3002<\/p>\n<ol>\n<li>WordPress\u5074\u3067<code>wp-json\/wp\/v2\/posts<\/code>\u306b\u30a2\u30af\u30bb\u30b9\u3067\u304d\u308b\u304b\u78ba\u8a8d\u3059\u308b\u3002\u30d6\u30e9\u30a6\u30b6\u3067URL\u3092\u53e9\u3044\u3066JSON\u304c\u8fd4\u3063\u3066\u304f\u308c\u3070\u758e\u901a\u3057\u3066\u3044\u308b\u3002<\/li>\n<li>X Developer Portal\u3067\u30a2\u30d7\u30ea\u306e\u30d1\u30fc\u30df\u30c3\u30b7\u30e7\u30f3\u304c\u300cRead and Write\u300d\u306b\u306a\u3063\u3066\u3044\u308b\u304b\u78ba\u8a8d\u3059\u308b\u3002Read only\u306e\u307e\u307e\u3060\u3068401\u30a8\u30e9\u30fc\u304c\u8fd4\u308b\u3002\u30d1\u30fc\u30df\u30c3\u30b7\u30e7\u30f3\u5909\u66f4\u5f8c\u306f\u30c8\u30fc\u30af\u30f3\u306e\u518d\u751f\u6210\u304c\u5fc5\u8981\u306a\u5834\u5408\u304c\u3042\u308b\u3002<\/li>\n<li><code>tweepy.Client<\/code>\u306b\u6e21\u3059\u30ad\u30fc\u306e\u9806\u756a\u3068\u540d\u524d\u304c<code>.env<\/code>\u3068\u4e00\u81f4\u3057\u3066\u3044\u308b\u304b\u3092\u78ba\u8a8d\u3059\u308b\u3002\u5909\u6570\u540d\u306e\u30bf\u30a4\u30dd\u306b\u3088\u308b\u8a8d\u8a3c\u5931\u6557\u304c\u591a\u3044\u3002<\/li>\n<\/ol>\n<p>\u521d\u56de\u5b9f\u884c\u6642\u306f\u3001\u30b9\u30af\u30ea\u30d7\u30c8\u5185\u306b<code>print(tweet_text)<\/code>\u3092\u5165\u308c\u3066\u5b9f\u969b\u306e\u9001\u4fe1\u524d\u306b\u672c\u6587\u3092\u76ee\u8996\u78ba\u8a8d\u3059\u308b\u3053\u3068\u3092\u52e7\u3081\u308b\u3002\u4e88\u671f\u3057\u306a\u3044HTML\u30a8\u30f3\u30c6\u30a3\u30c6\u30a3(<code>&amp;amp;<\/code>\u306a\u3069)\u304c\u30bf\u30a4\u30c8\u30eb\u306b\u6df7\u5165\u3057\u3066\u3044\u308b\u3053\u3068\u304c\u3042\u308b\u3002WordPress REST API\u306e\u30bf\u30a4\u30c8\u30eb\u30d5\u30a3\u30fc\u30eb\u30c9\u306fHTML\u30a8\u30f3\u30b3\u30fc\u30c9\u3055\u308c\u305f\u72b6\u614b\u3067\u8fd4\u3063\u3066\u304f\u308b\u305f\u3081\u3060\u3002<code>html.unescape(title)<\/code>\u3092\u631f\u3080\u3053\u3068\u3067\u5bfe\u51e6\u3067\u304d\u308b\u3002<\/p>\n<pre><code class=\"language-python\">import html\n\ndef build_tweet_text(post: dict) -&gt; str:\n    title = html.unescape(post[&quot;title&quot;][&quot;rendered&quot;])  # \u30a8\u30f3\u30c6\u30a3\u30c6\u30a3\u3092\u30c7\u30b3\u30fc\u30c9\n    url = post[&quot;link&quot;]\n    max_title_len = 100\n    if len(title) &gt; max_title_len:\n        title = title[:max_title_len] + &quot;\u2026&quot;\n    return f&quot;{title}\\n\\n{url}&quot;\n<\/code><\/pre>\n<h3>\u5b9a\u671f\u5b9f\u884c\u306e\u8a2d\u5b9a(cron\u306e\u4f8b)<\/h3>\n<p>VPS\u4e0a\u3067\u3053\u306e\u30b9\u30af\u30ea\u30d7\u30c8\u3092\u6bce\u6642\u5b9f\u884c\u3059\u308b\u5834\u5408\u3001crontab\u306b\u4ee5\u4e0b\u3092\u8ffd\u52a0\u3059\u308b\u3002<\/p>\n<pre><code class=\"language-bash\">0 * * * * \/usr\/bin\/python3 \/home\/user\/wp_x_post\/main.py &gt;&gt; \/var\/log\/wp_x_post.log 2&gt;&amp;1\n<\/code><\/pre>\n<p>\u5b9f\u884c\u983b\u5ea6\u306f\u8a18\u4e8b\u306e\u66f4\u65b0\u30da\u30fc\u30b9\u306b\u5408\u308f\u305b\u3066\u8abf\u6574\u3059\u308b\u30021\u6642\u9593\u3054\u3068\u3067\u5341\u5206\u306a\u30b1\u30fc\u30b9\u304c\u307b\u3068\u3093\u3069\u3060\u3002\u305f\u3060\u3057\u3001\u30b9\u30af\u30ea\u30d7\u30c8\u304c\u7570\u5e38\u7d42\u4e86\u3057\u305f\u308a\u3001<code>posted_ids.json<\/code>\u304c\u7834\u640d\u3057\u305f\u308a\u3059\u308b\u3068\u672a\u6295\u7a3f\u8a18\u4e8b\u304c\u691c\u51fa\u3055\u308c\u306a\u304f\u306a\u308b\u3002\u904b\u7528\u6bb5\u968e\u3067\u306f\u5b9a\u671f\u7684\u306b\u30ed\u30b0\u3092\u78ba\u8a8d\u3059\u308b\u7fd2\u6163\u3092\u5165\u308c\u3066\u304a\u304f\u3002<\/p>\n<hr>\n<p>\u203b\u672c\u8a18\u4e8b\u306f2026-05-21\u6642\u70b9\u306e\u60c5\u5831\u306b\u57fa\u3065\u304d\u307e\u3059\u3002AI \u30e2\u30c7\u30eb\u3084 API \u306e\u4ed5\u69d8\u30fb\u6599\u91d1\u306f\u5909\u66f4\u3055\u308c\u308b\u3053\u3068\u304c\u3042\u308a\u307e\u3059\u3002\u6700\u65b0\u306f\u516c\u5f0f\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u3092\u3054\u78ba\u8a8d\u304f\u3060\u3055\u3044\u3002<\/p>\n<p>AI \/ tech \u306e\u9078\u629e\u306f\u8981\u4ef6\u3084\u74b0\u5883\u306b\u3088\u3063\u3066\u6700\u9069\u89e3\u304c\u5909\u308f\u308a\u307e\u3059\u3002\u672c\u8a18\u4e8b\u306f\u53c2\u8003\u60c5\u5831\u3067\u3001\u6700\u7d42\u7684\u306a\u6280\u8853\u5224\u65ad\u306f\u3054\u81ea\u8eab\u306e\u691c\u8a3c\u306b\u57fa\u3065\u3044\u3066\u304f\u3060\u3055\u3044\u3002<\/p>\n<hr>\n<h2>\u307e\u3068\u3081<\/h2>\n<ul>\n<li>WordPress REST API\u3067\u516c\u958b\u8a18\u4e8b\u3092\u53d6\u5f97\u3057\u3001<code>posted_ids.json<\/code>\u3067\u672a\u6295\u7a3f\u7ba1\u7406\u3059\u308b\u69cb\u6210\u304c\u30b7\u30f3\u30d7\u30eb\u3067\u52d5\u304b\u3057\u3084\u3059\u3044<\/li>\n<li>X API\u8a8d\u8a3c\u306fOAuth 1.0a\u306e4\u30c8\u30fc\u30af\u30f3\u65b9\u5f0f\u3092\u4f7f\u3046\u3002\u30d1\u30fc\u30df\u30c3\u30b7\u30e7\u30f3\u306e\u8a2d\u5b9a\u30df\u30b9\u304c\u6700\u3082\u591a\u3044\u539f\u56e0\u306a\u306e\u3067\u3001Read and Write\u306b\u306a\u3063\u3066\u3044\u308b\u304b\u3092\u5148\u306b\u78ba\u8a8d\u3059\u308b<\/li>\n<li>\u30bf\u30a4\u30c8\u30eb\u306eHTML\u30a8\u30f3\u30c6\u30a3\u30c6\u30a3\u554f\u984c\u306f<code>html.unescape()<\/code>\u3067\u51e6\u7406\u3059\u308b\u3002\u5c0f\u3055\u306a\u30dd\u30a4\u30f3\u30c8\u3060\u304c\u3001\u5b9f\u904b\u7528\u3067\u8a70\u307e\u308a\u3084\u3059\u3044\u7b87\u6240\u3060<\/li>\n<\/ul>\n<p>\u6b21\u306f\u3001\u6295\u7a3f\u672c\u6587\u306b\u30cf\u30c3\u30b7\u30e5\u30bf\u30b0\u3092\u81ea\u52d5\u4ed8\u4e0e\u3059\u308b\u51e6\u7406\u3068\u3001\u8a18\u4e8b\u30ab\u30c6\u30b4\u30ea\u5225\u306e\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u3092\u7d44\u307f\u5408\u308f\u305b\u308b\u69cb\u6210\u3092\u8a66\u3057\u3066\u307f\u305f\u3044\u3002<\/p>\n<p style=\"font-size:0.85em;color:#888;margin-top:2em;\">Photo by <a href=\"https:\/\/unsplash.com\/@jakubzerdzicki?utm_source=shimaken&#038;utm_medium=referral\" target=\"_blank\" rel=\"noopener nofollow\">Jakub \u017berdzicki<\/a> on <a href=\"https:\/\/unsplash.com\/?utm_source=shimaken&#038;utm_medium=referral\" target=\"_blank\" rel=\"noopener nofollow\">Unsplash<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>WordPress\u3067\u8a18\u4e8b\u3092\u516c\u958b\u3059\u308b\u305f\u3073\u306b\u3001\u624b\u3067X\u306b\u6295\u7a3f\u30ea\u30f3\u30af\u3092\u8cbc\u308a\u4ed8\u3051\u3066\u3044\u308b\u3002\u3053\u306e\u4f5c\u696d\u3001\u6708\u306b20\u301c30\u672c\u306e\u8a18\u4e8b\u3092\u904b\u7528\u3059\u308b\u3088\u3046\u306b\u306a\u308b\u3068\u3001\u3058\u308f\u3058\u308f\u3068\u6642\u9593\u3092\u98df\u3046\u3002 \u300cAPI\u3067\u81ea\u52d5\u5316\u3067\u304d\u308b\u306f\u305a\u300d\u3068\u8003\u3048\u308b\u4eba\u306f\u591a\u3044\u304c\u3001\u3044\u3056\u624b\u3092\u52d5\u304b\u3059\u3068\u6700\u521d\u306e\u8a8d\u8a3c\u307e\u308f\u308a\u3067\u3064\u307e\u305a\u3044\u3066\u653e\u7f6e\u3001\u3068\u3044\u3046\u30d1\u30bf\u30fc\u30f3\u3092\u3088\u304f\u805e\u304f\u3002WordPress REST API\u306e\u8a8d\u8a3c\u65b9\u5f0f\u3068X API\u65e7Twitter API v2\u306e\u8a8d\u8a3c\u65b9\u5f0f\u304c\u5225\u7269\u3067\u3042\u308b\u3053\u3068\u304c\u7406<\/p>\n","protected":false},"author":1,"featured_media":230,"comment_status":"","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"_xw_keep_modified_date":false,"footnotes":""},"categories":[86,105,84],"tags":[117,118,119,116,115,114,120,69,113,72],"class_list":["post-231","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-api-integration","category-web-backend","category-automation-pipeline","tag-api-","tag-application-passwords","tag-oauth-1-0a","tag-python-","tag-tweepy","tag-twitter-api-v2","tag-wordpress-6-5","tag-wordpress-rest-api","tag-x-api","tag-72"],"xw_count_pv":"10","_links":{"self":[{"href":"https:\/\/shimaken.com\/schnauzer\/wp-json\/wp\/v2\/posts\/231","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/shimaken.com\/schnauzer\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/shimaken.com\/schnauzer\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/shimaken.com\/schnauzer\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/shimaken.com\/schnauzer\/wp-json\/wp\/v2\/comments?post=231"}],"version-history":[{"count":0,"href":"https:\/\/shimaken.com\/schnauzer\/wp-json\/wp\/v2\/posts\/231\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/shimaken.com\/schnauzer\/wp-json\/wp\/v2\/media\/230"}],"wp:attachment":[{"href":"https:\/\/shimaken.com\/schnauzer\/wp-json\/wp\/v2\/media?parent=231"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/shimaken.com\/schnauzer\/wp-json\/wp\/v2\/categories?post=231"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/shimaken.com\/schnauzer\/wp-json\/wp\/v2\/tags?post=231"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}