WordPressで画像付きの記事を自動で投稿する

Table of Content

はじめに

WordPressのREST APIを使用して画像付きの記事を自動で投稿してみます。

環境

サーバー側
WordPress 5.2.4

クライアント側
Python 3.7.4

pip list
requests 2.22.0
Jinja2 2.10.3

事前準備

WordPressの認証には種類がいくつかありますが、今回はアプリケーションパスワードを使用します。

まずプラグインとしてApplication PasswordをWordPressにインストールします。

「ユーザ管理」→「あなたのプロフィール」画面で「Application Passwords」の項目が存在することを確認して投稿者権限を有するユーザ名を入力後、「Add User」ボタンを押下します。
image.png

パスワードが生成されるので控えておきます。
image.png

このユーザとパスワードの組み合わせでRESTAPIは動作しますが、ユーザ管理画面にはログインできません。また、管理画面から上記のパスワードをRevokeで取り消すことができます。

クライアントの実装例

まず、WordPressを操作するモジュールを用意します。

wordpress_ctrl.py

"""WORDPRESSの操作"""
import json
import os
import base64
import requests

class WordPressError(Exception):
    """WordPressのエラー情報"""
    def __init__(self, ctrl, status_code, reason, message):
        super(WordPressError, self).__init__()
        self.ctrl = ctrl
        self.status_code = status_code
        self.reason = reason
        self.message = message

class WordPressCtrl:
    """WordPressの操作"""

    def __init__(self, url, user, password):
        """初期化処理"""
        self.url = url
        auth_str = f"{user}:{password}"
        auth_base64_bytes = base64.b64encode(auth_str.encode(encoding='utf-8'))
        self.auth = auth_base64_bytes.decode(encoding='utf-8')

    def check_response(self, res, success_code):
        """WordPressからの応答をチェック"""
        try:
            json_object = json.loads(res.content)
        except ValueError as ex:
            raise WordPressError(self, res.status_code, res.reason, str(ex))
        if res.status_code != success_code:
            raise WordPressError(self, res.status_code, res.reason, json_object['message'])
        return json_object

    def add_post(self, title, content, categorie_ids=[], tag_ids=[]):
        """WordPressに記事を投稿"""
        headers = {
            'Authorization': 'Basic ' + self.auth
        }
        data = {
            'title': title,
            'content': content,
            'format': 'standard',
            'categories' : categorie_ids,
            'tags' : tag_ids
        }
        res = requests.post(f'{self.url}/wp-json/wp/v2/posts', json=data, headers=headers)
        return self.check_response(res, 201)

    def update_post(self, id, title, content, categorie_ids=[], tag_ids=[]):
        """WordPressの既存記事を更新"""
        headers = {
            'Authorization': 'Basic ' + self.auth
        }
        data = {
            'title': title,
            'content': content,
            'format': 'standard',
            'categories' : categorie_ids,
            'tags' : tag_ids
        }
        res = requests.post(f'{self.url}/wp-json/wp/v2/posts/{id}', json=data, headers=headers)
        return self.check_response(res, 200)

    def upload_media(self, path, content_type):
        """メディアのアップロード"""
        file_name = os.path.basename(path)
        headers = {
            'Authorization': 'Basic ' + self.auth,
            'Content-Type': content_type,
            'Content-Disposition' : 'attachiment; filename={filename}'.format(filename=file_name)
        }
        with open(path, 'rb') as media_file:
            data = media_file.read()
        res = requests.post(f'{self.url}/wp-json/wp/v2/media', data=data, headers=headers)
        return self.check_response(res, 201)

    def upload_png(self, path):
        """メディアにPNG画像を追加"""
        return self.upload_media(path, 'image/png')

    def upload_jpeg(self, path):
        """メディアにJPEG画像を追加"""
        return self.upload_media(path, 'image/jpeg')

つづいて、WORDPRESSに画像をアップロードして記事を追加するサンプルを以下に示します。
WordPressCtrlにはWORDPRESSのURL、ユーザー名、事前準備で作成したパスワードを指定してください。

from jinja2 import Template
from wordpress_ctrl import WordPressCtrl,WordPressError

data = {
    'data_list' : [
        { 
            'name': '阿多田太郎',
            'age' : 15,
            'image_path' : 'test1.png'
        },
        { 
            'name': 'アロハ太郎',
            'age' : 34,
            'image_path' : 'test2.png'
        }
    ]
}

wpctrl = WordPressCtrl('https://ワードプレスのURL', 'testuser', 'APIキー')

# 画像のアップロード
for item in data['data_list']:
    try:
        wpres = wpctrl.upload_png(item['image_path'])
        item['img_url'] = wpres['source_url']
    except WordPressError as ex:
        print(ex.status_code, ex.reason, ex.message)

html = """
<h2>結果</h2>
<table border=1>
    <tr>
      <th>名前</th>
      <th>年齢</th>
      <th>画像</th>
    </tr>
    {% for item in data_list %}
        <tr>
        <td>{{ item.name | e}}</td>
        <td>{{ item.age | e}}</td>
        <td><img src="{{ item.img_url | e}}" width=150/></td>
        </tr>
    {% endfor %}
</table>
"""
try:
    # 新規投稿
    wpres = wpctrl.add_post('タイトル', Template(html).render(data), [1], [3])
    print(wpres['id'])
    # 既存投稿の更新
    wpres = wpctrl.update_post(wpres['id'], 'タイトル(更新)', Template(html).render(data), [1,2], [3,4])
    print(wpres['id'], wpres['title'])

except WordPressError as ex:
    print(ex.status_code, ex.reason, ex.message)

上記のプログラムを実行するとメディアに2つ画像が追加されます。
image.png

また投稿一覧に記事が1つ追加されます。
image.png

記事のプレビューは下記の通りです。
image.png

参考:

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です