まとまっている最近の記事がないのでメモ。
やること
- Railsから、WordPressにREST API経由で投稿する
- APIの認証には、Application Passwordsプラグインを利用する(インストール・パスワード発行済とします)
- Application Passwordsで発行したユーザ名、パスワードは、Railsのcredentials.ymlで管理する
環境
- Ruby 2.6.0
- Rails 5.2.2
- WordPress 5.2.1
- Application Passwords 0.1.0
記事内で利用する設定値
項目 | 設定値 |
---|---|
WordPressのサイトURL | https://example.com |
WordPress ユーザ名 | wp-user |
wp-user用のAPIパスワード | aaaa bbbb cccc dddd eeee ffff |
API投稿時の公開状態 | draft(下書き) |
credentialsの設定
$ EDITOR="vi" bin/rails credentials:edit
wp_api_username = 'wp-user'
wp_api_password = 'aaaa bbbb cccc dddd eeee ffff'
保存しておく。
投稿クラス作成
今回は、ServiceクラスとしてWordPressへの投稿機能を作成します。
※Serviceクラス自体邪道とも言われているので、場所はそれぞれの環境下で最適な場所を選んでください。
※あるモデルのデータを投稿するのであれば、そのモデル内でもいいと思います。
# frozen_string_literal: true
require 'net/http'
require 'open-uri'
Class WpApiPostService
API_URL = 'https://example.com/wp-json/wp/v2/posts'
def initialize(title, body, categories, tags)
@title = title
@body = body
@categories = categories
@tags = tags
end
def api_post
uri = URI.parse(API_URL)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
req = Net::HTTP::Post.new(uri.path)
req.content_type = "application/json"
req.set_form_data(article_setting)
req.basic_auth(Rails.application.credentials.wp_api_username, Rails.application.credentials.wp_api_password)
response = http.request(req)
if response.code == '201'
Rails.logger.info('Successfully posted WP API')
else
Rails.logger.warn(['---Failed to WP API Post---', response.code, response.message, response.body].join("\n"))
end
end
private
def article_setting
{
title: @title,
content: @body,
status: 'draft',
categories: @categories,
tags: @tags
}
end
end
APIのURLは、WordPressのURLにwp-json/wp/v2/postsをくっつけた値です。
記事のタイトル、本文、カテゴリ、タグを引数として渡せば、API投稿がされます。
WpApiPostService.new('テストタイトル', '<h2>テスト本文</h2>', '1, 222, 333', '2, 20').api_post
正常に投稿がされれば、response.codeで201が返ってきます。
カテゴリとタグ
カテゴリとタグは、IDを指定します。また、複数選択する場合、配列ではなく、カンマ区切りのIDの文字列を渡します。投稿例の第3引数と第4引数が例となっています。
(Pythonから投稿する例では配列だったんですけど、Rubyでは配列の最初の要素のみ適用されるだけでちゃんと動きませんでした。)
作ってるときに遭遇したエラー
401 Unauthorized
ベーシック認証時のIDとPASSの構成に間違えがありませんか?
注意点は、このAPIにおけるユーザ名がWordPressのユーザ名のことを指すという点です。
1とか2とかのWordPressのUserIDでも、Application Passwords作成時の名前のことでもないです。
400 Bad Request
api_postメソッド内、uri/http/req の属性値の設定が間違っていたため、正常に動作しなかった模様。開発上は、squidのプロキシ経由で接続しているので、squidのzero size replyが表示される状態でした。
502 Bad Gateway
cloudfrontなどを使って、管理側にSSL接続するときに、 http.use_ssl = true が抜けていると、オリジンサーバに接続できずに502が返ってくるようです。