WordPress の API を用いて記事の投稿を行う必要がでてきた。以前 ruby を利用して記事を投稿するスクリプトを書いたことがあったが、今回は利用しているサーバーの関係上、PHP で書かなければならない。メモ代わりに残しておこう。
WordPress API の利用方法
WordPress では以下の URL に対してアクセスすることで API を利用できる。
http://example.com/wp-json/wp/v2/
例えば投稿一覧やタグの一覧などであれば、Webブラウザ上から以下の URL にアクセスすることで json 形式でデータを取得可能だ。
http://example.com/wp-json/wp/v2/posts
http://example.com/wp-json/wp/v2/tags
一方で投稿を行うには権限が必要だ。Wordpress の管理画面のユーザー一覧画面から API で利用するユーザーを選択し、「Application Passwords の欄からパスワードを生成しよう。
生成すると HOGE FUGA PIYO HOGE FUGA PIYO
というような 4*6 の文字列が表示される。この文字列とユーザー名を利用して認証を行う。パスワードは一度しか表示されないので注意しよう。
ユーザー名とパスワードを Authorization ヘッダーに base64 エンコードを行って渡してやることで投稿を行えるようになる。
$response = wp_remote_post( 'https://example.com/wp-json/wp/v2/posts', array(
'headers' => array(
'Authorization' => 'Basic ' . base64_encode( 'USER_NAME:PASS WORD PASS WORD PASS WORD' ),
),
'body' => $article
) );
WordPress API を利用して記事を投稿する
それではスクリプトを書いていこう。
WordPress API を利用して画像を投稿する
画像を投稿するには /media に対して画像を送信すれば良い。
public function upload_image($image_url) {
$data = wp_remote_get($image_url);
$response = wp_remote_post('https://example.com/wp-json/wp/v2/media', array(
'headers' => array(
'Authorization' => 'Basic ' . base64_encode( $api_user_name.':'.$api_password ),
'Content-Disposition' => 'form-data;filename=' . basename($image_url)
),
'body' => $data["body"]
) );
$data = json_decode($response['body']);
return $data->id;
}
といってもぐぐって出てきたものをそのまま利用しているのだが。
画像を投稿するとその ID が返り値として取得できる。投稿のアイキャッチ画像として利用する場合はこの id を featured_media_id に入れる。
WordPress API を利用してカテゴリーやタグを投稿する
カテゴリーとタグは API では categories や tags などにアクセスすることで一覧の取得や新規作成が行える。これらは名前が違うだけで WordPress の内部処理的にはほぼ変わらないのでまとめてやる。
カテゴリーやタグを新規作成する場合は以下のように行う。
# $term_name is categories or tags
$response = wp_remote_post( 'https://example.com/wp-json/wp/v2/' . $term_name, array(
'headers' => array(
'Authorization' => 'Basic ' . base64_encode( $api_user_name.':'.$api_password ),
),
'body' => array('name' => $term)
) );
$data = json_decode($response['body']);
if ($data->code == 'term_exists') {
$data->data->term_id;
} else { // new
$data->id;
}
カテゴリーやタグは新規登録を行う際にすでに同じ名前のものがあれば登録せずに "term_exists" を返してくれる。ここで取得した ID を投稿時に渡してやることでカテゴリーやタグを投稿に付与できる。
WordPress API を利用して投稿を行う
これらを組み合わせて投稿を行うスクリプトを作成する。
require_once( '../public/wp-load.php' );
define('WP_API_BASE_URL', 'https://example.com/wp-json/wp/v2/');
define('WP_API_USER_NAME', 'example_user');
define('WP_API_PASSWORD', 'HOGE FUGA PIYO HOGE FUGA PIYO');
class WordPressApi {
# local
public $base_url = WP_API_BASE_URL;
public $api_user_name = WP_API_USER_NAME;
public $api_password = WP_API_PASSWORD;
// https://gist.github.com/kurozumi/72a86e7c5775ae22e6d58e74972699c6
public function upload_image($image_url) {
// if use remote file
$data = wp_remote_get($image_url);
$response = wp_remote_post( $this->base_url . 'media', array(
'headers' => array(
'Authorization' => 'Basic ' . base64_encode( $this->api_user_name.':'.$this->api_password ),
'Content-Disposition' => 'form-data;filename=' . basename($image_url)
),
'body' => $data["body"]
) );
$data = json_decode($response['body']);
return $data->id;
}
// $term_name should be tags or categories
// $terms array of terms
public function register_or_retrieve_terms($term_name, $terms) {
// いちいち POST して存在確認するのは無駄なので先にリストを取得する
$response = wp_remote_get( $this->base_url . $term_name . '?per_page=100' );
$current_terms = json_decode($response['body']);
$ids = array();
foreach ($terms as $term) {
$ret = array_filter($current_terms, function($a) use ($term) {
return $a->name == $term;
});
if ($ret) {
$a = array_pop($ret);
array_push($ids, $a->id);
continue;
}
// register
$response = wp_remote_post( $this->base_url . $term_name, array(
'blocking' => true,
'headers' => array(
'Authorization' => 'Basic ' . base64_encode( $this->api_user_name.':'.$this->api_password ),
'Expect' => '',
),
'body' => array('name' => $term)
) );
$data = json_decode($response['body']);
if ($data->code == 'term_exists') {
array_push($ids, $data->data->term_id);
} else { // new
array_push($ids, $data->id);
}
}
return $ids;
}
public function post($article) {
$response = wp_remote_post( $this->base_url . 'posts', array(
'headers' => array(
'Authorization' => 'Basic ' . base64_encode( $this->api_user_name.':'.$this->api_password ),
),
'body' => $article
) );
$data = json_decode($response['body']);
return $data->id;
}
}
$wa = new WordPressApi();
$image_url = 'https://example.com/test.jpg';
$featured_media_id = $wa->upload_image($image_url);
$categories = array('ほげ');
$tags = array('foo');
$article = array(
'title' => 'タイトル',
'status' => 'draft',
'content' => '本文',
'categories' => $wa->register_or_retrieve_terms('categories', $categories),
'tags' => $wa->register_or_retrieve_terms('tags', $tags),
'excerpt' => 'excerpt',
'slug' => 'this is slug',
'featured_media' => $featured_media_id,
'meta' => array(
'test_meta_key' => 'test_meta_value',
)
);
$wa->post($article);
こんな感じに書いてやれば API で記事を投稿できる。実際に書いたものをブログ用に適当に書き直したものなのでどこか間違いはあるかもしれない。
というわけでメモ代わりに残しておこうと思う。
コメント