Help us understand the problem. What is going on with this article?

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

はじめに

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

参考:

mima_ita
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away