カスタム投稿タイプでpermalink設定がうまくできないときの対策を無い知恵絞って考えた。

現在WP案件でカスタム投稿タイプを派手に使用しているのですが、permalink設定から躓いちゃいました。そもそものpermalink設定をガン無視されてしまいました。カスタム投稿タイプさんから。(マルチ化の有無なんてのも影響はしてると思うのですが)

カスタム投稿タイプでpermalink設定をできないかググってみたら方法はいくつかありました。

1.Custom Post Permalinksというプラグインを使う

これは、かなり有望かと思ったのですが、2011年8月11日現在ネット上でこのプラグインが見つかりません。これ使えばいいよと示唆してくださるブログは多々あれど、その実体には探せども探せども辿りつかず。まるで蜃気楼のようです。

で、おそらくは不具合や諸事情で公開を停止しているのだろうと判断し、適当なところで断念。

2.カスタム投稿タイプの設定をCMS pressというプラグインで行う

カスタム投稿タイプの設定をするためのプラグインは有名所としてCustom Post Type UIプラグインなんかがありまして、実際これは使いやすいのですが、Custom Post Permalinksとは相性が悪いらしい。で、こちらのCMS pressですが、設定できる項目がやや少なめで、カスタム投稿タイプを設定できるだけでも御の字感があります。でも、管理画面にpermalink設定があるんです。で、設定してみたら普通にそれが有効。これは結構最強かも。

でも、こちらは設定したpermalink以外のURLに書き換えることができないんです。記事の編集画面にpermalinkの編集ボタンさえ出ない。これは案件の仕様によっては現実的ではありません。

結論として、どちらも一長一短というか、帯に短し襷に長しというか、ケッ、使えねえじゃねえか、というかそんな感じ。

で、そもそもクライアント要望として必ず実現しなければならなかったことは、URL末尾をデフォルトでpost_idにすること。permalinkではそれが実現できないなら、値を何とかして書き換えるしかないですよね。

そこで、流用できそうなプラグインとして思いついたのが、MTstyle Postname For WPでした。これ、元々は2chの有志がさくっと書いたのがネットで出まわっており、実は僕は本来の配布元を知りませんので、ソースでの掲載という形にさせてもらいます。これ、意外といつもお世話になってます。結構オススメです。

/*
* Plugin Name: MT Style Post Name
* Description: スラッグに強制的にpost_idを挿入する
* Author: 449
* Plugin URI: http://pc10.2ch.net/test/read.cgi/blog/1163599919
* Version: 0.1
* */
add_filter('sanitize_title','sanitize_title_numalpha_only',9);
function sanitize_title_numalpha_only($title) {
	return preg_replace('/[^%a-zA-Z0-9 ¥(¥)_-]/', '-', $title);
}

処理の流れとしては、入力されたタイトルを引っ張ってきて2バイト文字を除去し、残った1バイト文字をハイフンでつなげた文字列を返す。1バイト文字列が全く入っていなかった場合には、post_idを返す、といった感じです。

post_idを持ってくる処理は、恐らくスラッグに不適切な文字列が送られてきた場合は自動的にコア部分でpost_idを返すような仕様になっているらしく(このプラグインを停止した状態で、タイトルに’—‘とか入れて試したら、強制的にpost_idになる)要は2バイト文字列が入っていた場合には、sanitize_title_numalpha_onlyの返り値としてスラッグに英数のみか、もしくは不適切な値が返されていてpost_idに変換される、ってことのようです。ならこれ、returnの値としてそれらの文字列返したら、常にpost_idになんじゃないの?と思いました。で、やってみました。

※20110816追記
以下のやり方は、ver.3.1にアップグレードしたら管理画面のjsが誤動作するようになりました。もともとの処理が、入力されたタイトルのサニタイズのタイミングを使っているようなんですが、どうやらバージョンが上がっていくにつれその処理があちこちに挟み込まれてるみたいで、なんでかんでも1バイト化しちゃうとまずいみたいです。下の記述をもう少し条件づけすればいいんでしょうけど、とりあえず違う方法で対処しようと思います。以下は参考程度にお願いいたします。

return preg_replace('/[^%a-zA-Z0-9 ¥(¥)_-]/', '-', $title);
↓
return '';//空を返す

上のように変更。

結果、まんまと成功して、なにがなんでもスラッグにpost_idを入れてくるプラグインの出来上がりです。

でもこのままだとスラッグを書き直すことができないです。なにを書いてもpost_idに変換されちゃいます。
あと、sanitize_titleという、実行のきっかけにしている関数が意外にあちこちで使われているっぽくて、空の値とか返しちゃうとページの表示でエラーになるらしく、NOT FOUNDになってしまいます。

そこで、2バイト文字列がタイトルやスラッグに含まれた場合にのみpost_idに書き換える処理にしてみました。そうすれば、書きなおして以降はスラッグの文字列をそのまま返すような流れとなるので、エラーになることも無いですし、半角英数なら任意の値に書き直すことも可能です。

return '';
↓
if(mb_strlen($title) == strlen($title)){
	return $title;//2バイト文字が含まれていない場合はそのまま値を返す
}else{
	return '';//2バイト文字が含まれていたら空を返し、post_idの代入を促す
}

これで、一応動くようにプラグインの改修完了。

<?php
	add_filter('sanitize_title','sanitize_title_numalpha_only',9);
	function sanitize_title_numalpha_only($title) {
		if(mb_strlen($title) == strlen($title)){
			return $title;//2バイト文字が含まれていない場合はそのまま値を返す
		}else{
			return '';//2バイト文字が含まれていたら空を返し、post_idの代入を促す
		}
	}
?>

仕様としては
・日本語タイトルは強制的にスラッグをpost_idに変更
・スラッグの変更は、マルチバイト文字列が含まれない場合のみOK。
こんな感じです。

上のソースをそのままphpとして保存して。pluginフォルダにアップしたらそれで動きます。

※20110930 上記でも日本語周りに問題アリのようです。ブタマンさんが、改良したコードを公開してくれていますので、そちらも参考にしてみてください。

少々余談、カスタム投稿タイプの設置について。

カスタム投稿タイプは、functions.phpに記述を追加すればプラグインを使わずに設置することが可能なのですが、使ったほうが設置自体は楽です。でも設定できる内容の幅とか、プラグイン同士の相性なんかもあるので、functions.phpでの設置にはそれはそれでメリットが。でもコード書くのは面倒。

そんなとき、Custom Post Type UIプラグインには、このプラグインで設置したカスタム投稿タイプをfunctions.phpに書く為のコードを吐き出す機能がついているので、それを使うのはひとつの方法かもしれません。とりあえずプラグイン入れてカスタム投稿タイプ設定してコードを吐き出してfunctions.phpに転記すれば、立ち上げのややこしさを多少軽減できるかも。

あと、設定項目が少ないと評したCMS pressですが、CMS pressで書いたカスタム投稿タイプの設定を、functions.phpにも同様に書いて、CMS pressでは設定できない値を補填するような感じで補うことができるようです。同じ設定項目を二重に書いた場合の優先度はCMS pressの方が高いようでした。長時間運用したわけではないので検証が十分ではないですが、新規投稿や編集程度は全く問題ありませんでした。

と、いうわけで、実はこれは全部自分用メモ。

あとで自分でまた使おう。

※20110812 少し書き直しました。