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のインストーラを実行すると、すぐにDockerの初期化が始まります。
「新規サイト作成」メニューから「新規WordPressサイト」を選択します。
次に、WordPress管理者アカウントの認証情報を設定します。
DevKinstaはスタンドアロンアプリケーションとして機能します。これで、WordPressサイト(「サイトを開く」ボタン)とWordPress管理画面(「WP管理画面」ボタン)の両方が使えるようになります。
次に、ウェブサイトのSSL/HTTPSの有効化を行います。SSL証明書を使うことで、ウェブサイトのセキュリティを強化できます。
次に、DevKinstaの「サイトを開く」ボタンをクリックします。ブラウザの新規タブでWordPressサイトのトップページが表示されます。
このWordPressサイトを自由に編集していくことができます。とは言え今回は、PythonによるWordPress REST APIを介したアクセスについて、設定を行う必要があります。
DevKinstaの「WP管理画面」ボタンをクリックし、ユーザーとパスワードを入力してWordPress管理画面に移動します。
ログインすると、WordPress管理画面が表示されます。
WordPressは、標準ではCookie認証を使用しています。しかし、REST APIを使って操作を行うには、WordPress REST APIへのアクセスを許可するかたちで認証を行う必要があります。
これには、Application Passwordsを利用します。WordPressサイトで簡単に24桁の文字列を生成することができ、ウェブサイトの管理権限を持つユーザーと紐付けて使用します。
Application Passwordsを使用するには、管理画面の「プラグイン」メニューをクリックし、「Application Passwords」を検索します。このプラグインをインストールし、有効化してください。
パスワードの作成を始めるには、まず、「ユーザー」メニューを展開し、「ユーザー一覧」をクリックします。
次に、管理者ユーザー名の下にある「編集」をクリックします。
プロフィールページをスクロールダウンし、「Application Passwords」セクションを見つけます。ここで、アプリケーションパスワードの名前を指定します。このパスワードは、後でPythonアプリのリクエストを認証し、REST APIを利用するのに使用します。
名前を入力して「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
- Windows→
-
- Mac/Linux→
.venv/bin/activate
- Mac/Linux→
次に、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_posts
とget_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アプリが取得した投稿の一覧を表示するには1を、投稿を選択するには2を選択します。
コードで投稿を作成する
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の投稿を新規作成することができます。
再度1を選択すると、今作成したばかりの投稿のIDとタイトルが返されます。
また、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、タイトル、コンテンツを指定して、既存の投稿を更新することができます。
オプション2を選択し、更新した投稿のIDを入力すると、先ほど編集した投稿の詳細が表示されます。
コードで投稿を削除する
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の既存の投稿を削除します。
注意)「List Posts」を実行しても、削除した投稿が表示される場合があります。
投稿が正しく削除されているかどうか確認するには、数秒待ってから「List Posts」を実行してください。これで完了です。
まとめ
WordPress REST APIとPythonのHTTPクライアントライブラリを活用することで、PythonアプリとWordPressの連携が実現しました。REST APIの特徴を活かし、PythonアプリからWordPressサイトを遠隔操作できます。また、Pythonをうまく使いこなせば、好みの構造でコンテンツの自動作成すら可能になります。
DevKinstaは、ローカル環境でのWordPressサイトの作成と開発を加速させるツールです。WordPressのテーマやプラグインの開発にも便利です。Dockerベースの自己完結型のインストールモデルにより、楽々デプロイメントを実現しています。
あなたはPythonとWordPressを組み合わせた経験はお持ちですか?コメント欄でお聞かせください。
WordPress REST APIの基本はこちらで解説しています。あわせてご覧ください。
コメントを残す