WordPressプラグインの中に、Push7というプラグインがあります。最新バージョンで3.0.7となっています。これはブラウザなど該当サイトが記事更新などした際に、プッシュ通知をするプラグインです。(Push7 は現在、Chrome(Android とデスクトップ) に対応とされています。)利用者はそれほど多くないのかもしれませんが、WordPressバージョン6.7や6.8ではテストされていません。また、プラグインのサイトを見ると4年以上更新されていない状態です。
上記サイトには、以下のように記載されています。
このプラグインは WordPress の最新3回のメジャーリリースに対してテストされていません。もうメンテナンスやサポートがされていないかもしれず、最新バージョンの WordPress で使用した場合は互換性の問題が発生する可能性があります。
そのような中で使用するのか否か迷うところでもあるかと思われます。そんな中、以下のようなエラーが管理画面に出ることがあります。

Warning: session_start(): Session cannot be started after headers have already been sent in /home/サーバID/ドメイン名/public_html/wp-content/plugins/push7/classes/push7.php on line 59
上記エラー内容の原因は、session_start() が出力後に実行されていることに起因しています。そこで、init() メソッドが WordPressの admin_init フック で呼ばれていますが、admin_init が発火する時点では、すでに出力(ヘッダー)が送信されていることがあるため、以下の行でエラーになります。
このエラーは、session_start() を実行しようとした時点で すでにHTTPヘッダーが送信済み だったために発生しています。
WordPressでは、ヘッダー(Set-Cookieなど)を送る前に session_start() を実行する必要があります。しかし、プラグイン(この場合 push7)が session_start() を実行する前に空白やHTML、echo文などでヘッダーが送信されてしまったというのがこのエラーの直接的な原因です。
add_action('admin_init', array($this, 'init'));
問題の本質
以下の部分が問題です
public function init() {
if (!$this->is_session_started()) session_start();
…
}
public function init() {
if (!$this->is_session_started()) session_start();
...
}
この init() メソッドが「WordPressのフックよりも早いタイミング」で呼び出されている場合、すでに何らかの出力(HTML、空白、エコーなど)が始まっており、session_start() が実行できなくなっているのです。
修正方法(解決方法):セッション開始を安全なタイミングへ移動する
【推奨案】セッション開始を init フックの優先度1で行う。次のように、セッション開始処理だけを別メソッドに切り出して、より早いタイミングの init に移すのが安全です。
public function __construct() {
add_action('init', array($this, 'start_session_safe'), 1); // ← 追加(優先度1で先に実行)
add_action('admin_init', array($this, 'init')); // ← 本来の初期化処理
add_filter('plugin_action_links_'.PUSH7_BASE_NAME, array($this, 'add_setting_link'));
new Push7_Admin_Menu();
new Push7_Admin_Notices();
new Push7_Post();
new Push7_Sdk();
}
public function start_session_safe() {
if (!$this->is_session_started()) {
session_start();
}
}
このように修正すれば、WordPressが何か出力する前(ヘッダー送信前)にセッションを開始できるため、Warning: session_start(): Session cannot be started after headers have already been sent は発生しません。
なぜこれで解決するのか?
- init フック(優先度1)は、WordPressの内部処理が始まって間もない段階で呼ばれます。
- この時点では、まだ HTML 出力やヘッダー送信は行われていません。
- 一方、admin_init では一部の出力がすでに行われているケースがあり、そこで session_start() を呼ぶとエラーになります。
注意点
- session_write_close(); の呼び出しはそのままでOKです。
- ただし、init() 内でセッションの読み書きをしていないなら、そもそも session_start() 自体不要かもしれません(Push7の他の部分で使っているか要確認)。
長期対応 プラグインの作者に修正を依頼または自身でコードを改善ですが、ただし、長期的な対応としてはやはり開発者への連絡にて修正をしてもらうことです。
以下に、該当ファイル内のPush.phpのコードを全部記載しておきます。
<?php
class Push7 {
const API_URL = 'https://api.push7.jp/api/v1/';
const VERSION = '3.0.7';
public function __construct() {
add_action('init', array($this, 'start_session_safe'), 1);
add_action('admin_init', array($this, 'init'));
add_filter('plugin_action_links_'.PUSH7_BASE_NAME, array($this, 'add_setting_link'));
new Push7_Admin_Menu();
new Push7_Admin_Notices();
new Push7_Post();
new Push7_Sdk();
}
public function start_session_safe() {
if (!$this->is_session_started()) {
session_start();
}
}
public static function admin_url() {
return add_query_arg(array('page' => 'push7'), admin_url('options-general.php'));
}
public static function post_types() {
return array_merge(get_post_types(array('_builtin' => false)), array('post' => 'post'));
}
public static function appno() {
return get_option('push7_appno', '');
}
public static function apikey() {
return get_option('push7_apikey', '');
}
public static function user_agent() {
global $wp_version;
return sprintf(
"WordPress/%s; %s; Push7:%s/PHP%s",
$wp_version,
get_bloginfo('url'),
Push7::VERSION,
phpversion()
);
}
public static function sslverify() {
return get_option('push7_sslverify_disabled') === 'false';
}
public static function box_enabled() {
return get_option('push7_sdk_enabled') === 'true';
}
public static function is_session_started() {
if ( php_sapi_name() === 'cli' ) return false;
if ( version_compare(phpversion(), '5.4.0', '>=') ) return session_status() === PHP_SESSION_ACTIVE;
return !(session_id() === '');
}
public function init() {
$default_check_options = array(
'push7_sslverify_disabled',
'push7_sdk_enabled'
);
$settings_params = array(
'push7_blog_title',
'push7_appno',
'push7_apikey',
'push7_sslverify_disabled',
'push7_sdk_enabled'
);
foreach ($settings_params as $setting) {
register_setting('push7-settings-group', $setting);
}
foreach ($default_check_options as $option) {
if (!get_option($option)) update_option($option, "false");
}
foreach (get_categories() as $category) {
$opt = "push7_push_ctg_".$category->slug;
register_setting('push7-settings-group', $opt);
if (get_option($opt, null) === '1' || is_null(get_option($opt, null))) update_option($opt, 'true');
if (get_option($opt, null) === '') update_option($opt, 'false');
}
if(count(Push7::post_types()) >= 2) {
foreach (Push7::post_types() as $post_type) {
$opt = "push7_push_pt_".$post_type;
register_setting('push7-settings-group', $opt);
$default_value = $post_type === 'post' ? 'true' : '';
$opt_value = get_option($opt, $default_value);
if($opt_value === 'true' || $opt_value === '') continue;
if($opt_value === 'false') {
update_option($opt, '');
continue;
}
update_option($opt, $default_value);
}
} else {
$opt = 'push7_push_pt_post';
$default_value = 'true';
$opt_value = get_option($opt);
if($opt_value !== $default_value) {
update_option($opt, $default_value);
}
}
session_write_close();
}
public function add_setting_link($links){
return array_merge($links, array('<a href="'.menu_page_url('push7', false).'">設定</a>'));
}
}
上記コードを該当phpファイルのディレクトリに(wp-content/plugins/push7/classes/ ディレクトリに)上書きアップロードします。必ずバックアップを取ってからご使用ください。
新着コメント