WordPressのKtaiStyleプラグインで、ログイン状態を保持したい場合、

WordPressのKtaiStyleプラグインで、ログイン状態を保持したい場合、

 WordPressのコードをみて「あー、PHPフレームワークってこういう方向(あえてglobal依存にしちゃう)がいいのかもしれないなぁ」とかちょっと思ったりもした今日この頃。

 ケータイ向けにしたい→会員向けなのでログイン必須→どうやって対応すんの?と思ってちょっと調べたところ、KtaiStyleがログイン処理もケータイ向けにやっててよさげだと思ったのですが、ログインセッション保持はあくまで管理画面向けで、通常画面ではセッション保持をしていないらしい。

 どーしたものかとソースコードを眺めていたところ、画面出力の直前にパッチを当ててStickyQueryを付ければいいんじゃね? ということで「ktai-style/ktai_style.php」にこんな修正をしてみた:


(略)

public function output() {
	if (is_robots() || is_feed() || is_trackback()) {
(略)
	if (function_exists('mb_http_output')) {
		mb_http_output('pass');
	}

	// sticky-query begin
	if (is_user_logged_in() and !$this->get('cookie_available')) {
		$sid = $this->admin->get_sid();
		ini_set('session.use_trans_sid', 1);
		ini_set('session.use_only_cookies', 0);
		session_name(KtaiStyle_Admin::SESSION_NAME);
		session_id($sid);
		session_start();
	}
	// sticky-query end

	header ("Content-Type: $mime_type; charset=$iana_charset");
	echo $buffer;
	exit;
}
(略)

――要するに出力直前にPHPのセッションとtrans_sidを有効にして、PHP側でクエリを追加してもらう事にしたんですな。

($bufferを書き換えるのはいろいろ面倒くさいので)

 これでなんか上手く動いているっぽい? と思ったら、セッションIDがPHPの制限に引っかかったため、セッションIDの生成部分(ktai-style/admin/class.php)もちょっとだけ変更:


(略)
private function make_sid() {
	$salt = wp_salt();
	$rand = uniqid(mt_rand(), true);
	$sid = base64_encode(hash_hmac('sha1', $rand, $salt, true));
	//return str_replace(array('+', '/', '='), array('_', '.', ''), $sid);
	return str_replace(array('+', '/', '='), array('-', ',', ''), $sid);
}
(略)

 これでうまく動いている――気がする。

(outputとmake_sidがフックできるといいのかなーと思いつつ、他に需要はないだろうしなぁ)

 このままだとセッションを使ってプラグインを使ってると動かないはずなので、

  • KtaiStyleプラグインが動作するタイミングで ini_setとセッションの名前・SIDをセットする
  • 出力前にsession_start()されてなかったら、session_start()するようにする

――のようにしたほうがいいのだろうけれど。

 みなさんどうやっているのかねぇ。

フッタ等での「ログイン/ログアウト」表記(追記:2011-11-11)

 ログイン/ログアウトを表示するために ks_login_link という関数が用意されているのですが、ログインしたあとのページを指定できるようになってればいいのに、とかちょっと思ったのでそういう関数を作ってみた:



/* ==================================================
 * @param	string  $redirect_to
 * @param	string  $before
 * @param	string  $after
 * @param	boolean $echo
 * @param	string  $accesskey
 * @param	string  $label
 * @return	string  $output
 */
function ks_login_link_redirect() {
	$defaults = array(
		'redirect_to' => '',
		'before'    => '',
		'after'     => '',
		'echo'      => true,
		'accesskey' => '',
		'anchor'     => __('Log in'),
		'anchor_logout' => __('Log out'),
		'before_logout' => NULL,
		'after_logout' => NULL,
	);
	$r = _ks_parse_arg(func_get_args(), $defaults);

	global $Ktai_Style;
	$output = '';
	if ( isset($Ktai_Style->admin) ) {
		if (is_user_logged_in()) {
			$url = ks_get_logout_url(false, $r['redirect_to']);
			if ( isset($r['label_logout']) ) { // backward compati
				$r['anchor_logout'] = $r['label_logout'];
			}
			$anchor = $r['anchor_logout'];
			$before = isset($r['before_logout']) ? $r['before_logout'] : $r['before'];
			$after = isset($r['after_logout']) ? $r['after_logout'] : $r['after'];
		} else {
			$url = ks_get_login_url(false, $r['redirect_to']);
			if ( isset($r['label']) ) { // backward compati
				$r['anchor'] = $r['label'];
			}
			$anchor = $r['anchor'];
			$before = $r['before'];
			$after = $r['after'];
		}
		$output = $before . sprintf('%s', $url, ks_accesskey_html($r['accesskey']), $anchor) . $after;
		if ($r['echo']) {
			echo $output;
		}
	}
	return $output;
}

/*
// ks_login_link() が redirect_to に対応すれば下記でOKになるはず:
function ks_login_link_redirect() {
	$defaults = array(
		'redirect_to' => '',
		'before'    => '',
		'after'     => '',
		'echo'      => true,
		'accesskey' => '',
		'anchor'     => __('Log in'),
		'anchor_logout' => __('Log out'),
		'before_logout' => NULL,
		'after_logout' => NULL,
	);
	$r = _ks_parse_arg(func_get_args(), $defaults);
	return ks_login_link($r);
}
*/

 ks_login_link と引数の順番が変わるのでそのまま置き換えるのはよくなさそうなので、別名にしたほうがよさげ(リダイレクト先は最初に指定できた方が利便性が高いので)。

 ks_login_linkでリダイレクト先が指定できるようになっていれば、ラッパ関数追加するだけで済むんだけどなぁ。

(これは作者さんに提案してもいいかもしれない)

KtaiStyleの通常ページでのログインセッションを、携帯向けテーマへの functions.php の追加のみで対応する(追記:2011-11-14)

 あれから色々調べてみたところ、下記のようなコードをテーマのfunctions.phpに追加することで通常画面でのログインセッション保持に対応できそうな感触。

 ざっくり解説すると

  • ks_sticky_query() では、ログイン状態でかつCookieが使えない場合にセッション用のクエリストリングを追加する
    • これを ktai_convert_links のフィルタに追加する
  • ks_sticky_query() では、ログイン状態でかつCookieが使えない場合に $shrinkage->convert_links()を適用する
    • これを ktai_split_page のフィルタに追加する

――ことで対応しています。

 それはそれとして、$shrinkage->shrink_content() ってデフォルトだと使われないのかな?

(もしかして設定変えれば使われるようになるんだろうか)

 最初 ktai_convert_links のフィルターに追加したのに動作してなくて、しばらく悩んでました。



function ks_sticky_query($link_html, $orig_html, $href, $label) {
	global $Ktai_Style;
	if (! is_user_logged_in()) return $link_html;
	if (ks_cookie_available()) return $link_html;

	$sid = $Ktai_Style->admin->get_sid();
	$name = KtaiStyle_Admin::SESSION_NAME;
	$qstr = http_build_query(array($name => $sid));

	$href .= (strpos($href, '?') === false)? '?': '&';
	$href .= $qstr;

	$html = "{$href}\">{$label}";
	return $html;
}
add_filter('ktai_convert_links', 'ks_sticky_query', 10, 4);

function ks_sticky_query_filter($buffer) {
	global $Ktai_Style;
	if (! is_user_logged_in()) return $buffer;
	if (ks_cookie_available()) return $buffer;

	return $Ktai_Style->shrinkage->convert_links($buffer);
}
add_filter('ktai_split_page', 'ks_sticky_query_filter', 19, 1);

 実際には前述の ks_login_link_redirect() もfunctions.phpに追加して使っています。