wp rest api 「このユーザーとして投稿を編集する権限がありません。」のエラーに2日間はまったけど解決
事の顛末
わたしはGoogleAppsScriptでWordPressのRestAPIを使おうと思っていました。POSTリクエストでWordPressの自動投稿をしようと思ったのですが「このユーザーとして投稿を編集する権限がありません。」というエラーが出続けておりなかなか解決ができませんでした。解決した方法は最後に書きますがここまでたどり着くのに2日くらいかかってしまったので、その途中経過も書き記しておこうと思います。
Application Passwordプラグインは必要なのか?
WordPressで自動投稿を行うには「認証」が必要なのですが、その事について調べていると「Application Passwordプラグイン」を入れるという古い情報がいまだにあります。現在はWordPressの標準機能としてアプリケーションパスワードを発行できる機能があります。ですので「Application Passwordプラグイン」は入れなくてよいということになります。
wp rest apiの認証方法はJWT認証やBasic認証がある。
ちょっと解決方法の話と主旨はそれますが「このユーザーとして投稿を編集する権限がありません。」を解決するのにBasic認証だけでなくJWT認証などもためしまし。しかし解決にはいたりませんでした。JWT認証はトークンを発行して認証を行いますが、こちらも「アプリケーションパスワード」が必要なことには変わりありません。
.htaccessの編集は必要なのか
ネットの情報を調べているとwp rest apiのpostリクエストで401エラーが出る場合。「Apacheがヘッダー情報を削除してしまう」などの情報があります。この情報によると.htaccessにRewriteRule .* - [E=REMOTE_USER:%{HTTP:Authorization}]
を記述せよとのことだったのですが結果的に記述しようがしまいが変わりませんでした。
RewriteEngine On
RewriteRule .* - [E=REMOTE_USER:%{HTTP:Authorization}]
wp rest apiで投稿しようとすると403エラーになる場合もある
wp rest apiの403エラーに関しては「アクセス制限」が絡んでいる場合が多いようです。この場合サーバーの設定(海外からのアクセス制限など)を見なおすことによって解決できるようです。ちなみに私の場合はレンタルサーバーのロリポップを使っていますが、ロリポップの場合は海外アクセス制限やwp rest apiの制限などはありません。
「このユーザーとして投稿を編集する権限がありません。」原因はPHPが「CGI版」だったから
結論からかくとPHPの設定が「CGI版」だったからです。なぜこれに気づけたのかを書きたいと思います。
miniOrange WordPress REST API Authentication - Pluginを使って発覚
WordPress REST API Authentication | WordPress Plugin
miniOrange WordPress REST API Authentication - PluginはWordPress REST API への不正アクセスに対するセキュリティを提供するプラグインなのですが、はじめよくわからず使っていました。試しにリクエストを行ったところ下記のメッセージが表示されました。
Authorization header not received. Either authorization header was not sent or it was removed by your server due to security reasons.
「Authorization ヘッダーが受信されていません」とのことだったので調べたところ、このような不具合はPHPが「CGI版」だと起こることがわかりました。そのためPHPを「モジュール版」にしたところ認証が通るようになりました。
まとめると「このユーザーとして投稿を編集する権限がありません。」はCGI版だとヘッダー情報がみつからないのでwp rest apiの認証が通らない。なので「モジュール版」にするです。
GASでWP REST APIを使い自動投稿をするコード
WP REST APIの認証トラブルも解決したのでGASで自動投稿をする基本のコードを記します。以下のサンプルコードは他のサイトを見てもだいたい一緒かと思います。ポイントは「パスワード」はアプリケーションパスワードで生成したパスワードを設定することです。
function wordpresspost() {
let siteUrl = '自サイトのURL';
let title = '自動投稿テスト';
let content = 'これは自動投稿です。';
let apiUrl = siteUrl + 'wp-json/wp/v2/posts';
let user = 'wordpressのusername';
let pass = 'アプリケーションパスワードで生成したパスワード';
let headers = {
'Content-Type': 'application/json',
'Authorization': 'Basic ' + Utilities.base64Encode(user + ":" + pass)
};
let arguments = {
'title': title,
'content': content,
'status': 'draft',
'comment_status': 'closed'
}
let options = {
'method': 'POST',
'muteHttpExceptions': true,
'headers': headers,
'payload': JSON.stringify(arguments)
};
let response = UrlFetchApp.fetch(apiUrl, options);
let responseJson = JSON.parse(response.getContentText());
console.log(responseJson);
}
Discussion
自分も同様の問題でハマっていましたが今回の記事を読んで解決できました!
記載の通りPHP(CGI版)からPHP(モジュール版)に変更するとAuthorization ヘッダーを認識してくれました。
記事を書いて頂き本当にありがとうございました👍