タイトル自動化その6

カスタムポストのタイトルを自動化しよう【追記あり】

2012.08.16(木) WordPress, 機能, 関数
このエントリーをはてなブックマークに追加

またまたカスタムポストの話題です。カスタムポストは非常に便利で、特に決まった様式で、常時投稿しなければならないようなもの、例えば商用サイトであれば、商品の品名、型番、値段、サイズ、etc・・・、それらをカスタムフィールドとして定型化すれば、投稿が非常に楽になるわけです。
ボクの場合は、吹奏楽団体のHP管理をしていまして、練習スケジュールを、日付、時間、場所を定型化して投稿したいなと思ってました。その際に悩んだのが、その投稿に対してタイトルをどうするかということ。最初は日付をタイトルにと思いましたが、同日で違う場所での練習というのもあるので、いまいちよくないのと、その場合日付+時間+場所と、カスタムフィールドで入力したものを組み合わせてタイトル入力しなければならないので、手入力するのは面倒だなと感じたんですね。
カスタムポストは設定によってはタイトル登録をしないでも投稿可能なので、タイトル自体が不要かとも思ったのですが、いくつかの場面でなきゃないで困ったので、なんとか自動的にタイトル入力できないかと思ったところ、うまく自動化できたので紹介しておきます。


カスタムフィールドだけで入力したい

とにかく、日常業務(というほど大変ではないんですが)なので、必要事項を選択するだけで投稿できれば楽じゃん!という事で、こんな感じのカスタムポスト設定をします。

タイトル自動化その1



タイトルも本文も入力することなく、選択だけで投稿できるので非常に楽ちんです。投稿画面はこんな感じ。

タイトル自動化その2

この場合に、タイトルはどうなるのか?タイトルは入力はしないのですが、内部的には無いとDB構造上問題になるようで、この場合「自動下書き」というタイトルが自動的につきます。一覧を見るとこんな感じに。

タイトル自動化その3

[divider]

まあ、どうせカスタムポスト用のページは自作するので、そのページでタイトル出さなきゃいいかなと初めは思っていたんですが、いくつか問題があります。

すべては「自動下書き」になる・・・

WordPressの記事毎のタイトル表示関数といえば、the_titleですが、それを使うと当然、タイトルがすべて「自動下書き」になります。なので、アーカイブページなどでは、the_permalinkを使って、URLだけとって、リンク名は適当につくればそれでいいわけですが、例えばSingleページで、次の記事とか、前の記事などのリンクをつけようと思うと、それも全部が「自動下書き」になり、前後がなにかわからなくなります。もちろん、next_posts_linkや、previous_posts_linkの引数を工夫すれば、文字列を変えることも可能ですが、ちょっと面倒かなと思います。
タイトル自動化その4


その他、例えばその記事にコメントを有効にした場合は、どの記事にコメントをつけても、「自動下書き」にn件のコメントがあります、、、となってしまって、あとで見ようとしても、いったいどこにコメントがついたのかがわかりづらくなります。
それら諸々考えると、やっぱりタイトルつけた方が無難なわけです。

タイトル更新タイミングをキャッチせよ

こういった場合に便利なのが、フィルターフック。おそらく、タイトルがDBに登録される直前辺りで、いい感じのフックがあるはず、と思って調べたところ、title_save_preというのが良さそうということで、以下の関数をfunction.phpに追加しました。

function my_auto_title($title_message){

	global $post;

	/* ポストタイプがカスタムかどうかチェック */
	if( $post->post_type == 'lessons' ){
		/* カスタムフィールドの取得 */
		$lesson_date = get_post_custom_values('lesson_date');
		if( $lesson_date ){
			$title_message = date('m/d',strtotime($lesson_date[0]));
		}
		/* lesson_timeをキーとして、練習時間を取得 */
	    $lesson_time = get_post_custom_values('lesson_time');
	    if( $lesson_time  ){
	    	$title_message = $title_message . '(';
			$title_message = $title_message . $lesson_time[0];
	    	$title_message = $title_message . ')';
	    }
		/* lesson_placeをキーとして、練習場所を取得 */
	    $lesson_place = get_post_custom_values('lesson_place');
	    if( $lesson_place  ){
			$title_message = $title_message . ' at ';
			$title_message = $title_message . $lesson_place[0];
	    }

	}

	return $title_message;

}

add_filter('single_post_title', 'my_auto_title');
add_filter('the_title', 'my_auto_title');

たったこれだけのソースで、うまく行きました、便利ですね、フィルターフックは。title_save_preというフックは、タイトルをDBに更新する前に、登録された関数を呼び出すわけですが、その自作関数my_auto_titleでは、カスタムポストだったら、タイトルをカスタムフィールドを組み合わせて作成し、戻り値としてそのタイトルを返却しています。それで、DB自体にはそのタイトルが登録されるため、一覧にもちゃんと表示されています。

11/10追記
どうやら、title_save_preは下書き保存時のフィルターフックのようで、single_post_titleと、the_titleでフィルターフックしたほうが良さそうですので、修正しました。ただ、the_titleは結構幅広く使われているので、思わぬところに影響が出る可能性もあります。ボクの場合は、何故かカスタムメニューの項目名なども変わってしまったりして、もう少し考えた方がいいかもしれませんね。。。




もちろん、次へのリンクもちゃんとでます。
タイトル自動化その6


ただ、このアクションフックは、ググってもちゃんとした説明があまりなく、若干苦労しました。フックされるタイミングはわかるのですが、その時に呼び出す自作関数の引数が何か?これがよくわからなかったんですね。プログラム上は引数なしでもちゃんと呼ばれますし、WordPressは、グローバル変数が充実しているので、引数なくても大概はうまくいくんですが、今回はいまいちうまくいきませんで、、、、そんな時はソースを見るしかないということで、フック名title_save_preで検索することに。が、ヒットしない。

通常は、apply_filtersという関数を使用して、アクションフックに登録された関数を呼び出すはずなので、フック名で検索すれば出るんですが、変数を使っている場合もありますので。で、仕方なしに、apply_filtersを全検索してそれらしき個所をみつけたわけです。

wp_include/post.php

function sanitize_post_field($field, $value, $post_id, $context) {
	$int_fields = array('ID', 'post_parent', 'menu_order');
	if ( in_array($field, $int_fields) )
		$value = (int) $value;

	// Fields which contain arrays of ints.
	$array_int_fields = array( 'ancestors' );
	if ( in_array($field, $array_int_fields) ) {
		$value = array_map( 'absint', $value);
		return $value;
	}

	if ( 'raw' == $context )
		return $value;

	$prefixed = false;
	if ( false !== strpos($field, 'post_') ) {
		$prefixed = true;
		$field_no_prefix = str_replace('post_', '', $field);
	}

	if ( 'edit' == $context ) {
		$format_to_edit = array('post_content', 'post_excerpt', 'post_title', 'post_password');

		if ( $prefixed ) {
			$value = apply_filters("edit_{$field}", $value, $post_id);
			// Old school
			$value = apply_filters("{$field_no_prefix}_edit_pre", $value, $post_id);
		} else {
			$value = apply_filters("edit_post_{$field}", $value, $post_id);
		}

		if ( in_array($field, $format_to_edit) ) {
			if ( 'post_content' == $field )
				$value = format_to_edit($value, user_can_richedit());
			else
				$value = format_to_edit($value);
		} else {
			$value = esc_attr($value);
		}
	} else if ( 'db' == $context ) {
		if ( $prefixed ) {
			$value = apply_filters("pre_{$field}", $value);
			$value = apply_filters("{$field_no_prefix}_save_pre", $value);
		} else {
			$value = apply_filters("pre_post_{$field}", $value);
			$value = apply_filters("{$field}_pre", $value);
		}
	} else {
		// Use display filters by default.
		if ( $prefixed )
			$value = apply_filters($field, $value, $post_id, $context);
		else
			$value = apply_filters("post_{$field}", $value, $post_id, $context);
	}

	if ( 'attribute' == $context )
		$value = esc_attr($value);
	else if ( 'js' == $context )
		$value = esc_js($value);

	return $value;
}

44行目がそれに当たるわけですが、呼び出し時の引数としては$valueの一つだとわかります。$valueは、おそらくタイトル文字列だろうということで、ソースは完全には理解できませんでしたが、なんとなくそうかなとわかりました。
もっと、簡単なフックの呼び出し個所もありますので、わからなかったらソースを見るのがやはり一番かなと思われます。

ということで、タイトル入力をなくして楽したい方は、参考にしてみてくだされ!

“カスタムポストのタイトルを自動化しよう【追記あり】” への2件のコメント

  1. [...] カスタムポストのタイトルを自動化しよう【追記あり】 [...]

  2. [...] http://stepxstep.net/?p=1187 共有:クリックして Twitter で共有 (新しいウィンドウで開きます)Facebook で共有 (新しいウィンドウで開きます)クリックして Google+ で共有 (新しいウィンドウで開きます) [...]

コメントをどうぞ