Help us understand the problem. What is going on with this article?

WordPress でセッションを使うときに色々怒られた件

ただいま WordPress 案件が走っているため、
最近の投稿は WordPress に偏っています。偏っているのはいつものことですが。

事の始め

今ちょうど決済の部分を作っていまして、
セッションを使おうかなと。

WordPress でセッションを使うにはやっぱり session_start() だそうです。
重要なのはそのタイミング。

検索すると大抵の場合、init アクションフックでスタートするように書いてあります。
一応、多重起動防止の措置もしておいて・・・

functions.php
function init_session_start() {

    // セッションが開始されていなければここで開始
    if( session_status() !== PHP_SESSION_ACTIVE ) {

        session_start();
    }
}

add_action( 'init', 'init_session_start' );

上手くセッションが張れました。

セッションの使い方は一般的な方法なのであえて説明しません。
トークンを渡して POST で受け取り、返ってきたトークンがセッションのものと一致したら OK というありきたりな処理。

page.php
// 利用者が購入手続きを行ったとき
if ( isset( $_POST[ 'token' ] ) {

    // 正常なトークンを受け取った場合は購入処理
    if ( $_SESSION[ 'token' ] === $_POST[ 'token' ] ) {

        // 購入に係る処理とか色々
    }

    // 使用済みトークンを削除
    unset( $_SESSION[ 'token' ] );
}

// トークンを発行
$token = md5( uniqid( rand(), true ) );

// トークンをセッションに保存
$_SESSION[ 'token' ] = $token;

本題

セッションは簡単だなーと思っていたとき、ふとサイトヘルスで問題が増えていることに気付きました。

20200912_wordpress.png

問題1

アクティブな PHP セッションを検出

session_start() 関数の呼び出しによって PHP セッションが作成されました。これは REST API およびループバックリクエストを妨害します。HTTP リクエストを行う前に、session_write_close() を使ってセッションを閉じる必要があります。

問題2

REST API でエラーが発生しました

REST API は WordPress や他のアプリケーションがサーバーと通信する手段の1つです。たとえばブロックエディター画面は、投稿や固定ページの表示や保存に REST API を使用しています。

REST API リクエストはエラーのために失敗しました。
エラー: cURL error 28: Operation timed out after 10001 milliseconds with 0 bytes received (http_request_failed)

問題3

サイトでループバックリクエストが完了できませんでした

ループバックリクエストは予約イベントの実行に使用されます。またテーマやプラグインの組み込みエディターでは、コードの安定性の確認に使用されます。

サイトへのループバックリクエストは失敗しました。現在、依存する機能は想定どおりに動作していません。
エラー: cURL error 28: Operation timed out after 10001 milliseconds with 0 bytes received (http_request_failed)

問題4

バックグラウンド更新が正常に動作しない可能性があります

バックグラウンド更新は使用中の WordPress のバージョンにセキュリティ更新がリリースされた際、自動更新できることを保証します。

[警告] wp_version_check() フィルターが利用可能か確認できませんでした。
[OK] バージョン管理システムは検出されませんでした。
[OK] この WordPress サイトでは更新の実行の際に FTP 情報が必要となりません。
[OK] すべての WordPress ファイルが書き込み可能です。

固定ページに直接書いたら、それはそれで怒られました

session_start() を page.php に直接書いてみたら、案の定怒られました。

PHP Warning: session_start(): Cannot start session when headers already sent in /var/www/html/wptest/wp-content/themes/wptest/page.php on line 13

要するに、ヘッダーが何か書き出しちゃったらその後にセッション張ろうとしても無駄だよ、ということらしいです。

解決方法

多分、下記のプラグインか何かで衝突が発生したんだろうと思います。
(※根拠も自信もありません)

  • Advanced Custom Fields
  • All-in-One WP Migration
  • Classic Editor
  • Custom Post Type UI
  • Really Simple CSV Importer
  • WP Maintenance Mode
  • WP-Members

つまり、ヘッダーに何か書き出すより前でなおかつ、init アクションフックより後に実行されるアクションフックを探せば良いということになります。

以下はアクションフックの実行順を検証したというありがたいページです。
WordPressの主要なアクションフックが実行される順番を検証してみた | WEMO

これによると、
wp_head 以上で init 以下のアクションフックならイケそうです。
ページを表示する直前に呼び出される template_redirect は良いんじゃないかと。

functions.php
function init_session_start() {

    // セッションが開始されていなければここで開始
    if( session_status() !== PHP_SESSION_ACTIVE ) {

        session_start();
    }
}

add_action( 'template_redirect', 'init_session_start' );

無事、自作セッションを使いつつエラーを解消することに成功しました。
同じ事象でお困りの際はお試しください。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away