📮
(JS→PHP→WP)WP REST APIでWordPressに投稿する
概要
JavaScriptで入力されたコンテンツをPHPに送信し、PHPからWordPressに投稿を実行します。
この方法ではWordPressのログイン機能を使用せず、アプリケーションパスワードによる認証を行って投稿を作成します。
つまりアプリケーションパスワードさえわかってしまえば荒らし放題のため、認証情報を秘匿するためにわざわざPHPを間に挟んでいます。
くれぐれもクライアントサイドで認証情報を扱わないようにね。
アプリケーションパスワードの発行
WordPressのユーザー一覧から、「アプリケーションパスワード」を発行します。
(管理者権限以外のユーザーで発行するのが望ましいです。)
WordPress 5.6以降であれば標準機能となっていますが、それ以前の場合はプラグインを使用することで有効化できます。
「アプリケーションパスワードの名前」と、「発行したパスワード」を控えておきます。
トークンは再表示できません。
画像の投稿
まず、phpに投稿したいデータを送る。
JavaScriptのコード
<input type="file" onchange="addFile" accept="image/png, image/jpeg, image/gif" />
Create.js
let file;
// ファイルの取得
function addFile(e) {
// 何も選択されなかった場合
if (e.target === undefined || (e.target.files && e.target.files.length === 0)) {
return;
}
file = e.target.files[0];
// 画像のプレビューを行う場合
let _img = document.createElement('img');
_img.setAttribute("src", URL.createObjectURL(file) );
_img.setAttribute("alt", file.name);
document.body.appendChild(_img);
}
// ファイルの送信
async function postFile() {
if (file) {
// formDataを作成
const formData = new FormData();
formData.append("file", file);
// 画像を送信
const mediaResponse = await fetch("/AddMediaAPI.php", {
method: "POST",
body: formData,
});
const media_data = await mediaResponse.json();
if (media_data) {
if (media_data.error) {
alert("画像アップロードに失敗しました");
throw new Error(`HTTP error! status: ${JSON.stringify(media_data)}`);
} else {
// 投稿を作成するときに使用する画像のID
console.log(media_data.id);
}
}
}
}
そして、PHPでデータを受け取りcURLでREST APIを叩いてWPに画像を作成する。
PHPのコード
AddMediaAPI.php
<?php
// APIエンドポイントのURL
$url = 'https://sample.com/wp-json/wp/v2/media/';
// 認証コード(Base64)の作成
$token = "Basic " . base64_encode("name:password");
// ファイルの受け取り
$file = $_FILES['file'] ?? null;
if (!$file || $file['error'] !== UPLOAD_ERR_OK) {
// ファイルがない、またはアップロードエラーがある場合の処理
echo json_encode(array(
'error' => 'File upload failed',
'details' => $file ? $file['error'] : 'No file sent'
));
exit;
}
$request_header = [
'Authorization: ' . $token,
'Content-Disposition: attachment; filename="' . $file['name'] . '"',// filenameという名前のファイルをattachment(ダウンロード)する。
];
$cfile = new \CURLFile($file['tmp_name'],$file['type'],$file['name']);// ファイルパス、ファイル拡張子、ファイル名
$data = array('file'=> $cfile);// multipart/form-dataを指定しているので配列にする。
// cURLセッションを初期化
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);// アクセスするURL
curl_setopt($ch, CURLOPT_POST, true);// POST送信する
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);// 送信するデータを指定
curl_setopt($ch, CURLOPT_HTTPHEADER, $request_header);// リクエストヘッダを指定
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);// 送信先のSSL証明書を検証する(開発環境で使用)
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);// 送信結果を返却する
// APIリクエストを実行し、結果を取得
$response = curl_exec($ch);
// cURLエラーのチェック
if (curl_errno($ch)) {
echo json_encode(array(
'error' => 'cURL error: ' . curl_error($ch)
));
curl_close($ch);
exit;
}
// cURLセッションを終了
curl_close($ch);
// 結果をJSON形式で出力
header('Content-Type: application/json');
// 結果をJSON形式でデコード
$response_data = json_decode($response, true);
// ステータスコードの確認
$status = $response_data['data']['status'] ?? null;
if ($status !== 200) {
echo json_encode(array(
'error' => 'Image creation failed',
'details' => $response_data
));
exit;
}
// 成功の場合のレスポンス
echo json_encode($response_data);
本文の投稿・更新
データに投稿IDを含めれば、投稿の更新もできます。
PHPに投稿したいデータを送る
JavaScriptのコード
create.js
// 投稿を作成
async function createPost() {
const postResponse = await fetch("/AddPostAPI.php", {
method: "POST",
body: JSON.stringify({
title: content_title,
content: content_value,
author: 2,// アプリケーションパスワードを持つユーザーのID
status: "publish",
featured_media: content_image || null, // サムネイルの画像IDを設定
categories: [3,4],// カテゴリーのIDを指定
tags: [3,4],// タグのIDを指定
}),
});
const postData = await postResponse.json();
if (postData) {
if (postData.error) {
alert("投稿の作成に失敗しました");
throw new Error(`HTTP error! status: ${JSON.stringify(postData)}`);
} else {
console.log(postData);
}
}
}
PHPでデータを受け取り、cURLでREST APIを叩いてWPに投稿を作成する。
PHPのコード
AddPostAPI.php
<?php
// APIエンドポイントのURL
$url = 'https://sample.com/wp-json/wp/v2/posts/';
// 認証コード(Base64)の作成
$token = "Basic " . base64_encode("name:password");
$content = json_decode(file_get_contents('php://input'),true);
// $_GETや$_POSTなど、他のデータは取得できなくなる。
if (!$content) {
// データがない場合の処理
echo json_encode(array(
'error' => 'Data upload failed'
));
exit;
}
// サニタイズ処理
function recursive_htmlspecialchars($input) {
if (is_array($input)) {
return array_map('recursive_htmlspecialchars', $input);
} else {
return htmlspecialchars($input);
}
}
$title = filter_var($content['title'], FILTER_SANITIZE_STRING);
// $content['content']の中にネストされた配列やオブジェクトがある場合は、json_encodeする
$contents = json_encode(recursive_htmlspecialchars($content['content']));
$author = filter_var($content['author'], FILTER_VALIDATE_INT);
$status = filter_var($content['status'], FILTER_SANITIZE_STRING);
$featured_media = isset($content['featured_media']) ? filter_var($content['featured_media'], FILTER_VALIDATE_INT) : null;
$categories = recursive_htmlspecialchars($content['categories']);
$tags = recursive_htmlspecialchars($content['tags']);
// 投稿ID
$postId = isset($content['id']) ? $content['id'] : null;
// 投稿データの作成
$data = json_encode(array(
'title' => $title,
'content' => $contents,
'author' => $author,
'status' => $status,
'featured_media' => $featured_media,
'categories' => $categories,
'tags' => $tags,
));
$request_header = [
'Authorization: ' . $token,
'Content-Type: application/json'
];
// cURLセッションを初期化
$ch = curl_init();
if(!empty($postId)) {
// IDがある場合(投稿を更新する場合)
curl_setopt($ch, CURLOPT_URL, $url . $postId);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
} else {
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
}
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_HTTPHEADER, $request_header);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// APIリクエストを実行し、結果を取得
$response = curl_exec($ch);
// cURLエラーのチェック
if (curl_errno($ch)) {
echo json_encode(array(
'error' => 'cURL error: ' . curl_error($ch)
));
curl_close($ch);
exit;
}
// cURLセッションを終了
curl_close($ch);
// 結果をJSON形式で出力
header('Content-Type: application/json');
// 結果をJSON形式でデコード
$response_data = json_decode($response, true);
// ステータスコードの確認
$status = $response_data['data']['status'] ?? null;
if ($status !== 200) {
echo json_encode(array(
'error' => 'Image creation failed',
'details' => $response_data
));
exit;
}
// 成功の場合のレスポンス
echo json_encode($response_data);
Discussion