WordPressが人気のコンテンツ管理システム(CMS)となり得た経緯には、そのアプリケーションプログラミングインターフェース(API)が少なからず影響しています。WordPress REST APIにより、WordPressとさまざまな言語で書かれた他のアプリケーションとのやり取りが可能になります。

Pythonは拡張性の高いプログラミング言語です。その用途は多岐にわたり、構文は人間にとって読みやすいものとなっています。この特徴から、WordPressのコンテンツを遠隔管理するのに便利な選択肢です。

アプリケーションでのWordPress REST APIの使用例と、それのサポートにどのようにPythonが使えるのかイメージできるように、簡単な例をご紹介します。例えば以下の通りです。

  • テンプレートを使うことで、生データを(書式を整えたかたちで)投稿に素早く変換
  • DjangoとPythonでバックオフィスアプリケーションを構築し、オブジェクト固有の割引や販売イベントが発生するたびに、期間限定のオファーを表示
  • Pythonスクリプトを統合しWordPressサイト内で実行

以上を踏まえて、今回の記事では、WordPress REST APIと通信し操作を実行する、シンプルなPythonコンソールアプリケーションの作成方法をご紹介したいと思います。コードを役割ごとに分けて扱っていきます。

WordPressのインストールと設定

まず、開発マシンのローカル環境でWordPressサイトを作成しましょう。サーバーのアカウントを作成したり、ドメインを購入したりする必要がないため、WordPressをシンプルに扱うことができます。

WordPressをローカル環境で用意する前に、Apacheウェブサーバー、ローカルデータベース、(WordPressの記述に使用されている)PHPなど、特定のコンポーネントがコンピュータ上で実行されている必要があります。

この全ての管理に便利なのがDevKinstaです。すべての主要OSで利用可能な無料のローカルWordPress開発スイートとして、Kinstaが公開しています。このツールのご利用にKinstaのプラン契約は必要ありません。

DevKinstaは、Windows、Mac、およびLinuxで利用可能で、WordPressとその依存関係のすべてをローカルマシンに簡単にインストールできます。

DevKinstaのインストール前に、ローカル環境でDockerを実行する必要がありますので、まだの場合はDocker Engineをダウンロード、インストールしてください。

Docker Desktopをインストールした後、お使いのOSに合ったパッケージをダウンロードすることができます。

DevKinstaのインストール画面
DevKinstaのインストール画面

DevKinstaのインストーラを実行すると、すぐにDockerの初期化が始まります。

DevKinstaによりローカル環境でDockerが起動
DevKinstaによりローカル環境でDockerが起動

新規サイト作成」メニューから「新規WordPressサイト」を選択します。

DevKinstaの新規サイト作成メニュー
DevKinstaの新規サイト作成メニュー

次に、WordPress管理者アカウントの認証情報を設定します。

DevKinsta「新規WordPressサイト」選択後に表示されるフォーム
DevKinsta「新規WordPressサイト」選択後に表示されるフォーム

DevKinstaはスタンドアロンアプリケーションとして機能します。これで、WordPressサイト(「サイトを開く」ボタン)とWordPress管理画面(「WP管理画面」ボタン)の両方が使えるようになります。

DevKinstaのサイト情報パネル
DevKinstaのサイト情報パネル

次に、ウェブサイトのSSL/HTTPSの有効化を行います。SSL証明書を使うことで、ウェブサイトのセキュリティを強化できます。

DevKinstaの「SSLとHTTPS」
DevKinstaの「SSLとHTTPS」

次に、DevKinstaの「サイトを開く」ボタンをクリックします。ブラウザの新規タブでWordPressサイトのトップページが表示されます。

WordPressサイトのトップページ
WordPressサイトのトップページ

このWordPressサイトを自由に編集していくことができます。とは言え今回は、PythonによるWordPress REST APIを介したアクセスについて、設定を行う必要があります。

DevKinstaの「WP管理画面」ボタンをクリックし、ユーザーとパスワードを入力してWordPress管理画面に移動します。

WordPressのログインフォーム
WordPressのログインフォーム

ログインすると、WordPress管理画面が表示されます。

WordPressの管理画面
WordPressの管理画面

WordPressは、標準ではCookie認証を使用しています。しかし、REST APIを使って操作を行うには、WordPress REST APIへのアクセスを許可するかたちで認証を行う必要があります。

これには、Application Passwordsを利用します。WordPressサイトで簡単に24桁の文字列を生成することができ、ウェブサイトの管理権限を持つユーザーと紐付けて使用します。

Application Passwordsを使用するには、管理画面の「プラグイン」メニューをクリックし、「Application Passwords」を検索します。このプラグインをインストールし、有効化してください。

WordPressのプラグイン「Application Passwords」
WordPressのプラグイン「Application Passwords」

パスワードの作成を始めるには、まず、「ユーザー」メニューを展開し、「ユーザー一覧」をクリックします。

ユーザーメニューを拡張
ユーザーメニューを拡張

次に、管理者ユーザー名の下にある「編集」をクリックします。

WordPressの管理者インターフェース
WordPressの管理者インターフェース

プロフィールページをスクロールダウンし、「Application Passwords」セクションを見つけます。ここで、アプリケーションパスワードの名前を指定します。このパスワードは、後でPythonアプリのリクエストを認証し、REST APIを利用するのに使用します。

「Application Passwords」のセクション
「Application Passwords」のセクション

名前を入力して「Add New Application Password」ボタンをクリックすると、24文字のランダムなパスワードが生成されます。

新しいアプリケーションパスワードを生成完了
新しいアプリケーションパスワードを生成完了

次に、このパスワードをコピーして、後で使えるように安全な場所に保存してください。一度ページ(ポップアップ)を閉じると、後から確認することはできませんので、ご注意ください。

最後に、パーマリンクを設定する必要があります。WordPressでは、パーマリンクとアーカイブのURL構造を自分で作成することができます。例えば「Your First WordPress Website」というタイトルのWordPressの記事に、直感的なURLである「https://your-website.local:port/your-first-wordpress-website/」からアクセスできるように設定してみましょう。こうすることには、ユーザビリティや見た目の美しさの向上など、いくつかのメリットがあります。

パーマリンクを変更するには、「設定」にある「パーマリンク設定」をクリックします。ここで、「共通設定」を「投稿名」に変更します。

パーマリンクの設定を変更

投稿名」の構造でパーマリンクを設定することで、後からPythonのコードでJSON形式を使って記事を取得できるようになります。これを行なっておかないと、JSONのデコードエラーが発生します。

Pythonを使ってWordPressサイトを操作する方法

WordPressはPHPで書かれていますが、他のプログラミング言語やサイト、アプリからコンテンツにアクセスできるようにREST APIが用意されています。WordPressのコンテンツをRESTアーキテクチャで公開すると、JSON形式での利用が可能になります。その結果、他のサービスからWordPressと統合し(WordPressをローカル環境にインストールせずとも)作成、読み取り、更新、削除(CRUD)操作を実行することができます。

それでは、簡単なPythonアプリを構築し、WordPress REST APIを使用して投稿の作成、取得、更新、削除を行う方法をご紹介します。

Pythonプロジェクトとして新しくディレクトリを作成し、PythonWordPressのような名前を付けます。

../PythonWordPress

続いて、Pythonのパッケージを独立したものとして維持できるよう、プロジェクトの仮想環境を作成します。システムディレクトリからの分離により、バージョンの衝突を回避できます。venvコマンドを実行し、仮想環境を作成します。

python3 -m venv .venv

次に、.venv仮想環境を有効にするコマンドを実行します。このコマンドは実際のOSによって異なります。

 

    • Windows→ .venvScriptsactivate
    • Mac/Linux→ .venv/bin/activate

 

次に、WordPressのアカウントに関連する設定を保存します。アプリの設定とPythonのコードを分離するために、プロジェクトディレクトリに.envファイルを作成し、以下の環境変数をファイルに貼り付けます。

WEBSITE_URL="<>"
API_USERNAME="<>"
API_PASSWORD="<>"

Pythonアプリから上記のデータを読み込むのは簡単です。Python-dotenvパッケージをインストールすることで、アプリケーションが.envファイルから設定を読み込めるようになります。

pip install python-dotenv

次に、Pythonの非同期型HTTPクライアント/サーバーであるaiohttpをインストールします。

pip install aiohttp

続いて、app.pyというファイルに以下のコードを貼り付けます。

import asyncio

menu_options = {

1: 'List Posts',

2: 'Retrieve a Post'

}

def print_menu():

for key in menu_options.keys():

print (key, '--', menu_options[key] )

async def main():

while(True):

print_menu()

option = input_number('Enter your choice: ')

#Check what choice was entered and act accordingly

if option == 1:

print('Listing posts...')

elif option == 2:

print('Retrieving a post...')

else:

print('Invalid option. Please enter a number between 1 and 5.')

def input_number(prompt):

while True:

try:

value = int(input(prompt))

except ValueError:

print('Wrong input. Please enter a number ...')

continue

if value < 0:

print("Sorry, your response must not be negative.")

else:

break

return value

def input_text(prompt):

while True:

text = input(prompt)

if len(text) == 0:

print("Text is required.")

continue

else:

break

return text

if __name__=='__main__':

asyncio.run(main())

上のコードは、コンソールメニューを表示し、オプション選択のための数字の入力を求めるものです。次に、このプロジェクトを拡張し、すべての投稿を一覧表示したり、投稿IDを使用して特定の投稿を取得したりできるようにします。

コードで投稿を取得する

WordPress REST APIとのやり取りのために、新しいPythonファイルを作成します。wordpress_api_helper.pyという名前で、以下の内容のファイルを用意しましょう。

import aiohttp

import base64

import os

import json

from dotenv import load_dotenv

load_dotenv()

user=os.getenv("API_USERNAME")

password=os.getenv("API_PASSWORD")

async def get_all_posts():

async with aiohttp.ClientSession(os.getenv("WEBSITE_URL")) as session:

async with session.get("/wp-json/wp/v2/posts") as response:

print("Status:", response.status)

text = await response.text()

wp_posts = json.loads(text)

sorted_wp_posts = sorted(wp_posts, key=lambda p: p['id'])

print("=====================================")

for wp_post in sorted_wp_posts:

print("id:", wp_post['id'])

print("title:", wp_post['title']['rendered'])

print("=====================================")

async def get_post(id):

async with aiohttp.ClientSession(os.getenv("WEBSITE_URL")) as session:

async with session.get(f"/wp-json/wp/v2/posts/{id}") as response:

print("Status:", response.status)

text = await response.text()

wp_post = json.loads(text)

print("=====================================")

print("Post")

print("     id:", wp_post['id'])

print("     title:", wp_post['title']['rendered'])

print("     content:", wp_post['content']['rendered'])

print("=====================================")

上記のaiohttpライブラリの使用に注目してください。モダンな言語には通常、非同期プログラミングを可能にする構文とツールがあるものです。これにより、ウェブリクエスト、データベース操作、ディスクI/Oなどの操作と並行して、プログラムがタスクを実行でき、アプリケーションの応答性が向上します。Pythonには非同期プログラミングフレームワークの基盤としてasyncioがあります。そして asyncioとの連携のために構築されたライブラリがaiohttpで、Pythonで行われるHTTPクライアント/サーバー操作における非同期アクセスを実現しています。

上記のClientSession関数が非同期で実行され、sessionオブジェクトを返します。このオブジェクトを使用することで、今回のプログラムが/wp-json/wp/v2/postsのエンドポイントに対してHTTP GETを実行します。すべての投稿を取得するリクエストと特定の投稿を取得するリクエストの唯一の違いとして、URLルートでpost idパラメータが渡されます(/wp-json/wp/v2/posts/{id})。

続いては、app.pyファイルを開いて、importの記述を行いましょう。

from wordpress_api_helper import get_all_posts, get_post

次に、main関数を編集し、get_all_postsget_post関数を呼び出します。

if option == 1:

print('Listing posts...')

await get_all_posts()

elif option == 2:

print('Retrieving a post...')

id = input_number('Enter the post id: ')

await get_post(id)

そして、アプリを実行します。

python app.py

すると、アプリケーションのメニューが次のように表示されます。

Pythonアプリケーションのメニュー
Pythonアプリケーションのメニュー

ここで、Pythonアプリが取得した投稿の一覧を表示するには1を、投稿を選択するには2を選択します。

TPythonアプリを使って、投稿一覧、ユーザーが選択した1つの投稿を表示する
Pythonアプリを使って、投稿一覧、ユーザーが選択した1つの投稿を表示する

 

コードで投稿を作成する

PythonでWordPressの投稿を作成するには、まずwordpress_api_helper.pyファイルを開き、create_post関数を追加します。

async def create_post(title, content):

async with aiohttp.ClientSession(os.getenv("WEBSITE_URL")) as session:

async with session.post(

f"/wp-json/wp/v2/posts?content={content}&title={title}&status=publish"

, auth=aiohttp.BasicAuth(user, password)) as response:

print("Status:", response.status)

text = await response.text()

wp_post = json.loads(text)

post_id = wp_post['id']

print(f'New post created with id: {post_id}')

このコードはsessionオブジェクトのpost関数を呼び出し、REST APIのエンドポイントURLの横にあるauthパラメータを渡します。authオブジェクトには、WordPressのユーザーとApplication Passwordsを使って作成したパスワードが格納されます。次に、app.pyファイルを開き、create_postとメニューをインポートするコードを貼り付けます。

from wordpress_api_helper import get_all_posts, get_post, create_post

menu_options = {

1: 'List Posts',

2: 'Retrieve a Post',

3: 'Create a Post'

}

次に、3つ目のメニューオプションを追加します。

elif option == 3:

print('Creating a post...')

title = input_text('Enter the post title: ')

content = input_text('Enter the post content: ')

await create_post(title, f"{content}")

そして、アプリを実行し、オプション3を選択してみます。タイトルとコンテンツを指定して、WordPressの投稿を新規作成することができます。

PythonアプリでのWordPress新規投稿作成
PythonアプリでのWordPress新規投稿作成

再度1を選択すると、今作成したばかりの投稿のIDとタイトルが返されます。

Pythonアプリで新しい投稿のタイトルとIDを確認
Pythonアプリで新しい投稿のタイトルとIDを確認

また、WordPressサイトを開いて、この投稿を表示することもできます。

新しいWordPressの投稿をブラウザで表示
新しいWordPressの投稿をブラウザで表示

コードで投稿を更新する

wordpress_api_helper.pyファイルを開き、update_post関数を追加します。

async def update_post(id, title, content):

async with aiohttp.ClientSession(os.getenv("WEBSITE_URL")) as session:

async with session.post(

f"/wp-json/wp/v2/posts/{id}?content={content}&title={title}&status=publish"

, auth=aiohttp.BasicAuth(user, password)) as response:

print("Status:", response.status)

text = await response.text()

wp_post = json.loads(text)

post_id = wp_post['id']

print(f'New post created with id: {post_id}')

次にapp.pyファイルを開き、update_postとメニューをインポートするコードを記述します。

from wordpress_api_helper import get_all_posts, get_post, create_post, update_post

menu_options = {

1: 'List Posts',

2: 'Retrieve a Post',

3: 'Create a Post',

4: 'Update a Post'

}

そして、4つ目のメニューオプションを追加します。

elif option == 4:

print('Updating a post...')

id = input_number('Enter the post id: ')

title = input_text('Enter the post title: ')

content = input_text('Enter the post content: ')

await update_post(id, title, f"{content}")

次に、アプリを実行し、オプション4を試してみましょう。投稿ID、タイトル、コンテンツを指定して、既存の投稿を更新することができます。

Pythonアプリで投稿を更新
Pythonアプリで投稿を更新

オプション2を選択し、更新した投稿のIDを入力すると、先ほど編集した投稿の詳細が表示されます。

Pythonアプリで更新した投稿の情報を表示
Pythonアプリで更新した投稿の情報を表示

コードで投稿を削除する

REST APIに投稿IDを渡すことで、投稿を削除することもできます。

wordpress_api_helper.pyファイルを開き、delete_post関数を追加します。

async def delete_post(id):

async with aiohttp.ClientSession(os.getenv("WEBSITE_URL")) as session:

async with session.delete(

f"/wp-json/wp/v2/posts/{id}"

, auth=aiohttp.BasicAuth(user, password)) as response:

print("Status:", response.status)

text = await response.text()

wp_post = json.loads(text)

post_id = wp_post['id']

print(f'Post with id {post_id} deleted successfully.')

次にapp.pyファイルを開き、delete_postとメニューをインポートするコードを追加します。

from wordpress_api_helper import get_all_posts, get_post, create_post, update_post, delete_post

menu_options = {

1: 'List Posts',

2: 'Retrieve a Post',

3: 'Create a Post',

4: 'Update a Post',

5: 'Delete a Post',

}

そして、5番目のメニューオプションを追加します。

elif option == 5:

print('Deleting a post...')

id = input_number('Enter the post id: ')

await delete_post(id)

最後に、アプリを実行して、オプション5を試してみます。IDを指定し、WordPressの既存の投稿を削除します。

Pythonアプリで選択した投稿を削除する
Pythonアプリで選択した投稿を削除する

注意)「List Posts」を実行しても、削除した投稿が表示される場合があります。

Pythonアプリで投稿一覧を表示
Pythonアプリで投稿一覧を表示

投稿が正しく削除されているかどうか確認するには、数秒待ってから「List Posts」を実行してください。これで完了です。

まとめ

WordPress REST APIとPythonのHTTPクライアントライブラリを活用することで、PythonアプリとWordPressの連携が実現しました。REST APIの特徴を活かし、PythonアプリからWordPressサイトを遠隔操作できます。また、Pythonをうまく使いこなせば、好みの構造でコンテンツの自動作成すら可能になります。

DevKinstaは、ローカル環境でのWordPressサイトの作成と開発を加速させるツールです。WordPressのテーマやプラグインの開発にも便利です。Dockerベースの自己完結型のインストールモデルにより、楽々デプロイメントを実現しています。

あなたはPythonとWordPressを組み合わせた経験はお持ちですか?コメント欄でお聞かせください。

WordPress REST APIの基本はこちらで解説しています。あわせてご覧ください。

Salman Ravoof

独学のウェブ開発者、ライター、クリエイターでもあり、大の無料オープンソースソフトウェア(FOSS)好き。その他の好きなものは、科学、哲学、写真、芸術、猫、そして食。詳しい仕事情報はウェブサイトおよびXアカウントで公開している。