WordPressのREST APIでPythonから画像アップロード

ブログ

この記事では、Pythonを使用してWordPressサイトに画像をアップロードする方法について解説します。
画像のアップロード、上書きアップロード、重複確認付きアップロードなどを実装します。

準備:WordPress APIクライアントの設定

WordPress APIを利用するためには、まずWordPressサイトのURLと認証情報を設定する必要があります。認証は、Application Password、JWT、OAuth1のいずれかの方法を選択します。

この記事では認証の詳細には触れませんが、投稿の記事で説明した方法を使用します。

import requests

class WordPressClient:
    def __init__(self, wp_url, auth_method, auth_info):
        self.wp_url = wp_url
        self.auth_method = auth_method
        self.auth_info = auth_info
        self.headers = {}
        self.media_cache = {}

        # 認証設定
        self.set_auth()

    def set_auth(self):
        """ 認証設定を行う """
        if self.auth_method == "application_password":
            username = self.auth_info.get("username")
            password = self.auth_info.get("password")
            self.headers["Authorization"] = f"Basic {requests.auth._basic_auth_str(username, password)}"
        # 他の認証方法(JWT, OAuth1)も必要に応じて追加

    def request(self, method, endpoint, data=None, files=None):
        """
        WordPress APIへのリクエストを行う
        :param method: HTTPメソッド (GET, POST, etc.)
        :param endpoint: APIエンドポイント
        :param data: リクエストデータ
        :param files: ファイルデータ(画像アップロード用)
        :return: レスポンスオブジェクト
        """
        url = f"{self.wp_url}/wp-json/wp/v2/{endpoint}"
        response = requests.request(method, url, headers=self.headers, json=data, files=files)
        if not response.ok:
            raise Exception(f"Error: {response.status_code} - {response.text}")
        return response.json()

画像アップロードの実装

画像をWordPressにアップロードするための主な関数は以下の通りです。

upload_image メソッド

upload_image メソッドは、指定された画像ファイルをWordPressにアップロードする機能を提供します。画像がすでに存在する場合には、それを削除してからアップロードすることも可能です。

画像には直接的な上書き処理はありません。したがって、上書きしたい場合は、既存ファイルを削除して、新規にアップロードが必要です。

内部で使用している別のメソッドは後半で説明します。

def upload_image(self, image_path, overwrite=False, **kwargs):
    """
    画像をアップロードする
    :param image_path: アップロードする画像のパス
    :param overwrite: 既存の画像を上書きするかどうかのフラグ
    :param kwargs: 追加の画像データ(タイトル、説明など)
    :return: アップロードされた画像のID
    """
    # 画像ファイル名を取得
    image_name = image_path.split('/')[-1]

    # 画像の重複確認
    if overwrite:
        existing_image = self.get_media_by_name(image_name)
        if existing_image:
            # 既存の画像が見つかった場合、その画像を削除
            self.delete_image(existing_image)

    # 画像のアップロード
    with open(image_path, 'rb') as img_file:
        files = {
            'file': (image_name, img_file, 'image/jpeg')  # 画像のMIMEタイプは適宜変更
        }
        image_data = {key: value for key, value in kwargs.items() if value is not None}
        response = self.request("POST", "media", files=files, data=image_data)

    media_id = response.get('id')
    self.media_cache[image_name] = media_id
    return media_id

画像の存在確認と取得:get_media_by_name メソッド

get_media_by_name メソッドは、指定された画像名に一致する画像がすでに存在するかを確認し、存在する場合はそのIDを返します。

既存の画像が存在するか確認するために使用します。
IDとファイル名の情報は取得に時間がかかるので、別途関数を作成して、辞書形式で保持します。

def get_media_by_name(self, image_name):
    """
    指定した画像名で画像を検索し、存在する場合はその情報を返す
    :param image_name: 画像のファイル名(拡張子を含む)
    :return: 画像の情報(存在しない場合はNone)
    """
    if not self.media_cache:
        self.get_media_ids()
    return self.media_cache.get(image_name)

画像のIDとファイル名:get_media_idsメソッド

画像のIDとファイルの辞書は取得に時間がかかるので、辞書としてキャッシュに保存します。

def get_media_ids(self):
        """
        すべてのメディアのファイル名とIDを格納する辞書を取得する
        :return: メディアファイル名とIDの辞書
        """
        endpoint = "media"
        media_cache = {}
        page = 1
        per_page = 100  # 一度に取得するアイテムの数(必要に応じて調整)

        while True:
            response = self.request("GET", endpoint, data={'per_page': per_page, 'page': page})
            if not response:
                break

            for item in response:
                media_id = item.get('id')
                media_file = item.get('media_details', {}).get('file', '')
                media_cache[media_file] = media_id

            if len(response) < per_page:
                break

            page += 1

        self.media_cache = media_cache
        return media_cache

画像の削除:delete_image メソッド

delete_image メソッドは、指定した画像IDの画像をWordPressから削除します。
上書き処理にしたい場合に使用します。

def delete_image(self, image_id):
    """
    画像を削除する(強制的に削除するためのパラメータを追加)
    :param image_id: 削除する画像のID
    """
    endpoint = f"media/{image_id}?force=true"
    self.request("DELETE", endpoint)
    print(f"Image with ID {image_id} has been deleted.")

画像の詳細データの取得:get_media_by_idメソッド

idを指定して、その画像データの詳細を取得します。

    def get_media_by_id(self, media_id):
        """
        指定したメディアIDでメディアの情報を取得する
        :param media_id: メディアアイテムのID
        :return: メディアアイテムの情報(存在しない場合はNone)
        """
        endpoint = f"media/{media_id}"

        try:
            response = self.request("GET", endpoint)
            return response
        except Exception as e:
            print(f"Error retrieving media with ID {media_id}: {e}")
            return None

アップロード方法別の実装

画像には直接的な上書き処理はありません。したがって、上書きしたい場合は、既存ファイルを削除して、新規にアップロードが必要です。

ですので、アップロードのやり方にはいくつかパターンが考えられます。そのパターンごとに処理を行うメソッドを作成します。

  • 0はmedia_id取得のみ
  • 1は存在しない場合のみupload
  • 2は上書き
  • 3は新規アップロード
def upload_image_type(self, image_path, upload_type=1,overwrite=False, **kwargs):
        """
        画像をアップロードする
        :param image_path: アップロードする画像のパス
        :param upload_type: アップロードの方法を指定 0はmedia_id取得のみ、1は存在しない場合のみupload、2は上書き,3は新規アップロード
        :param kwargs: 追加の画像データ(タイトル、説明など)
        :return: アップロードされた画像のID
        """
        image_name = image_path.split('/')[-1]
        if upload_type == 0:
            media_id = self.get_media_by_name(image_name)
        elif upload_type == 1:
            media_id = self.get_media_by_name(image_name)
            if media_id is None:
                media_id = self.upload_image(image_path, **kwargs)
        elif upload_type == 2:
            media_id = self.upload_image(image_path, overwrite=True, **kwargs)
        elif upload_type == 3:
            media_id = self.upload_image(image_path, **kwargs)
        else:
            raise ValueError("Unsupported upload type")

        return media_id

実行例

以下に、WordPressClientクラスを使用して画像をアップロードする方法の例を示します。

# 必要なライブラリをインポート
from datetime import datetime

# WordPressクライアントの設定
wp_url = "https://your-wordpress-site.com"
auth_method = "application_password"  # 認証方法(例: application_password, jwt, oauth1 など)
auth_info = {
    "username": "your-username",
    "password": "your-application-password"
}

# WordPressClientのインスタンスを作成
wp_client = WordPressClient(wp_url, auth_method, auth_info)

# アップロードする画像のパスを指定
image_path = "path/to/your/image.jpg"

# 画像をアップロードする(既存の画像があれば上書きする)
media_id = wp_client.upload_image(image_path, overwrite=True, title="Image Title", description="Image Description")

print(f"Uploaded Image ID: {media_id}")
  1. 認証情報の設定:
    wp_url: WordPressサイトのURLを指定します。
    auth_method: 使用する認証方法を指定します。この記事では、application_passwordを使用します。
    auth_info: 認証情報(ユーザー名とアプリケーションパスワード)を辞書形式で提供します。

  2. WordPressClientのインスタンス化:
    – 設定した情報を使用してWordPressClientのインスタンスを作成します。この時点で、指定した認証方法に応じて適切に認証が設定されます。

  3. 画像のアップロード:
    upload_imageメソッドを使用して画像をアップロードします。このメソッドには画像のパス、上書きするかどうかのオプション、および画像のタイトルや説明などの追加情報を渡すことができます。
    overwrite=Trueを指定することで、同じ名前の画像が既に存在する場合、それを削除して新しい画像をアップロードします。

  4. アップロードした画像のIDの取得:
    – アップロードが成功すると、media_idとして新しくアップロードされた画像のIDが返されます。このIDを使用して、WordPress内で画像を管理することができます。

まとめ

ここまでの内容で、REST APIを使って、記事の投稿、画像のアップロード、カテゴリーやタグの取得が可能になりました。

ここまでで作成したWordPressClientの内容を整理した記事は以下で確認してください。

また、このクラスを使うことで、画像入りのブログ記事原稿を投稿する方法は以下になります。

タイトルとURLをコピーしました