このサイトは鳥画像ギャラリーサイトなんですが、投稿日、鳥種、撮影日、投稿に属する画像の枚数などの情報が一目でわかる投稿一覧ページがあった方が便利なので作成しました。
と、いっても通常のindex.phpとそんなに変わることはなく、1ページに読み込む投稿の数を多く指定することと、表示することが投稿日、鳥種(タイトル)、撮影日、画像の枚数など本文以外の限られた内容に絞ることぐらいです。
あとはデザイン的なことだけで、固定ページにて作成すればいいだけのこと、と、思ったのですが。

実際の投稿一覧ページは ← これです。
画像ファイル名や学名での検索機能なんてのも付加機能として付けましたが、とりあえず固定ページ用に作成したテンプレートのリスト表示部分は以下の通り。

<div id="content">
<p id="pagetitle">post list</p>

<div class="listdiv">
	<ul>

		<?php
			$kugiri='<li><span class="square">◆Post date&ensp; : &ensp;Species name&ensp; : &ensp;Scientific name&ensp; : &ensp;upload images&ensp; : &ensp;Date picture taken</span></li>';

			//1ページに表示する投稿の数を変更します。
			query_posts("&posts_per_page=120&paged=$paged");
					
			$countfor=1;
		?>
		<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
		<?php
			if($countfor%30==1){
				//一定の行数ごとに表題を挿入しています。
				echo $kugiri;
			}
		?>
		<li><a href="<?php echo get_permalink($post->ID); ?>" class="listdivmain" title="Go this post page."><?php echo get_the_date(); ?> : <?php the_title(); ?></a> : 
		<?php
			//投稿についているタグ(鳥種名)を取得
			$tagsinfo=get_the_tags();
			foreach($tagsinfo as $tagsvalue){
				$tags_slug=$tagsvalue->slug;
			}
			//タグの各要素を取得
			$tag_properties = get_term_by('slug',$tags_slug,'post_tag');
			echo "<a href=\"JavaScript:sendtagslug('x".$tags_slug."')\" class=\"greycolor\" title=\"Go this bird images page.\">".$tag_properties->description."</a>";

			//投稿に属する画像の数を得るため各画像の情報を取得
			$attachments = get_children(array('post_type'=>'attachment','post_mime_type'=>'image','post_parent'=>$post->ID));
			$numatch=count($attachments);//画像の数を取得
			echo ' : '.$numatch;
			$countfor++;
			echo " : <span class=\"smallblue\">".get_post_meta($post->ID,'撮影日時',true)."</span>";
			echo "</li>";	
		?>
		<?php endwhile;endif; ?>
	</ul>
</div>
</div>

1ページに表示する投稿の数を指定する場合は、11行目query_posts()を使います。引数の&posts_per_page=120がその部分、この場合は120個の指定。
もう一つの引数&paged=$pagedは、ページナビゲイションにプラグインのWP-PageNaviを使用している場合に、query_posts()を使って動作しなかったときに動くようにすることができます。
25~31行目は投稿についているタグから学名などの情報を得るための処理。
get_the_tags()で投稿に付けられているタグを取得。通常一つとは限らないので、返り値はオブジェクトの配列となります。ちなみにここのサイトの場合は投稿についているタグはほとんどが1つだけです。
得られたタグのslugからget_term_by()でそのタグがもっている各情報を取得しています。ここの場合各鳥の学名はタグのdescription(説明)に入れて使っているのでそれを得るためです。
34~35行目は投稿に属する画像の数を得るための処理。
get_children(array( 'post_type'=>'attachment', 'post_mime_type'=>'image', 'post_parent'=>$post->ID)) で投稿に属する画像の情報を得て、count()で数を出します。
最後のget_post_meta($post->ID,'撮影日時',true)は撮影日はカスタムフィールドの値として設定してあるのでそれを取得しています。

これにてとりあえずは投稿一覧リストの出力は出来るようになったのですがとても重い。
やはり120個もの投稿を読み込むせいか、早くても6秒ほどページを表示するのに要します。これは環境にも左右されるところですが、自分の環境でトップページが3秒かかることはほとんどないので、その倍以上です。
サーバーにも負担をかけていそうなので、早くて負担の少ない処理の仕方を考えました。

まず投稿を得る部分ですが、ここの場合、必要な情報は投稿ID、投稿日、投稿タイトル、投稿へのリンク、鳥の学名、画像の数、だけ。
投稿ID、投稿日、タイトル、リンクはSQLを使ってwp_postsテーブルからその4つに絞って得たほうが軽そうです。
ただ、SQLでデータを限定して取得して使う場合、ページネーションの処理も考えねばならなくて、そのためには全投稿数が必要となるので、それも先にSQLにて取得する必要がありますね。

その辺りのページネーションのやり方は「画像一覧ページ」でほとんどそのまま使わせてもらったこの本、のやり方をここでもほとんどそのまま活用させていただいています。

本当にためになったありがたい本です。
全投稿数を得て、urlから現ページ数を得るとともにページネーション用に必要な各数値を設定し、そのページに表示するのに必要なデータを取得する流れは以下の様です。

$per_page=120;//1ページの表示投稿数

//全投稿数を得るためのsqlの組み立て
$sql = <<< HERE
SELECT COUNT(a.ID) FROM $wpdb->posts a
WHERE a.post_type = 'post'
AND a.post_status = 'publish'
HERE;

//sqlを実行して$pcountに全投稿数を得る
$pcount=$wpdb->get_var($sql);

// 全ての投稿の数から全ページ数を求める
$page_counts=ceil($pcount / $per_page);
// URLからページ番号を得る
$page_no=intval($wp_query->get('paged'));
if ($page_no < 1) {
	$page_no = 1;
}elseif($page_no > $page_counts) {
	$page_no = $page_counts;
}
// オフセットを求める
$offset = ($page_no - 1) * $per_page;

//必要なデータを得るためのsqlの組み立て
$sql=<<<HERE
SELECT a.ID,a.post_date,a.post_title,a.guid FROM $wpdb->posts a
WHERE a.post_type = 'post'
AND a.post_status = 'publish'
ORDER BY a.post_date DESC
LIMIT $offset, $per_page
HERE;

//sqlを実行して結果を配列にて取得
$postids=$wpdb->get_results($sql,ARRAY_N);

16行目のurlからページ番号を得る$page_no=intval($wp_query->get('paged'))の式に関して。
1ページ目でない時はurlにそのページ番号を示す?paged=2のようにオプションが付いています。
このオプションは$wp_query->get('paged')で得る事ができます。intval関数で数値に変換してページ番号として使用しています。
23行目のオフセットは1ページ目でない時に、何個目の投稿データから読み出すかの値です。
最後の35行目のSQLを実行してデータを得る処理の $wpdb->get_results($sql,ARRAY_N)は引数にARRAY_Nを指定することで戻り値を配列で得ています。

で、この部分を変更した効果はというと、あまり体感的に変化はないようです。
次に、タグを取得する処理をやめて、必要な鳥名と学名はカスタムフィールドから得る処理に変更しました。
投稿に付けた投稿タグはそのslugには英名が、descriptionに学名が設定してあるので、それらのデータは投稿タグから得ることもできますが、それとは別に各投稿のカスタムフィールドにも鳥の和名、英名、学名、撮影日が入力してあります。
データがタブっているので無駄ですが、カスタムフィールドの使い方を取得しておきたかったという事があります。
カスタムフィールドにはdataIDという項目もあり、既に入力済みの鳥に関しては入力した投稿IDをdataIDに指定することで撮影日以外はその投稿IDのカスタムフィールドデータから得るようにしています。
どちらにせよ撮影日のデータはカスタムフィールドから得るしかないので、まとめて一度にカスタムフィールドの値を取得したほうが負荷が少ないように思います。

//変更前のタグを取得する処理
$tagsinfo=get_the_tags($pid);
foreach($tagsinfo as $tagsvalue){
	$tags_slug=$tagsvalue->slug;
}
$tag_properties = get_term_by('slug',$tags_slug,'post_tag');
echo "<a href=\"JavaScript:sendtagslug('x".$tags_slug."')\" class=\"greycolor\" title=\"Go this bird images page.\">".$tag_properties->description."</a>";

//変更したカスタムフィールドからデータを得る処理
$custdata=get_post_custom($pid);
$pastdata=$custdata["dataID"];
$dpicdt=end($custdata["撮影日時"]);
if($pastdata[0]==0){
	$spname=end($custdata["英名"]);
	$spname=str_replace(" ","_",strtolower($spname));
	$biname=end($custdata["学名"]);
}else{
	$custdata=get_post_custom($pastdata[0]);
	$spname=end($custdata["英名"]);
	$spname=str_replace(" ","_",strtolower($spname));
	$biname=end($custdata["学名"]);
}
echo "<a href=\"JavaScript:sendtagslug('x".$spname."')\" class=\"greycolor\" title=\"Go this bird images page.\">".$biname."</a>";

2~7行目がタグから取得する変更前の処理。10行目以降がカスタムフィールドから読み出す変更した処理です。
get_post_custom(投稿ID)は投稿IDからその投稿に入力されているカスタムフィールドの全ての値をまとめて取得しますが、戻り値はカスタムフィールド名をkeyにした連想配列になっていて、ちょっと使いづらいのはそれぞれの各keyの値はたとえ単独であっても配列となっています。単独のデータであることがわかっているのでend関数にて値を得ています。
この変更により気持ち早くなったような気もしますが、あまりはっきりと感じられる効果はありませんね。

実は、はじめからなんとなく一番負荷が掛かっているような感じがするポイントは投稿に属する画像の数を得る処理だったのですが、他の方法が思い浮かびませんでした。
現状ではget_children()で画像の情報を取得してcount()でその配列の数を出していますが、画像を表示するわけではないので各画像の情報などは不必要です。
単純にSQLで画像の数だけ求めた方が負荷が少ないかもしれません。

$sql=<<<HERE
SELECT COUNT(a.ID) FROM $wpdb->posts a
WHERE a.post_parent=${pid}
AND a.post_mime_type LIKE 'image/%'
AND a.post_type='attachment'
HERE;

$numatch=$wpdb->get_var($sql);

${pid}はループの中で既に得られている投稿のIDを入れている変数です。
で、結果は?

この変更はとても効果的でした。
体感的にもかなり表示が早くなり、秒的にもほとんどの場合で2秒とかからなくなりました。
トップページの表示よりも確実に早くなりましたね。
やはりこの部分が負荷が大きかったということのようです。
と、いうことで最終的には以下のようにしました。

<div id="content">
<p id="pagetitle">post list</p>

<div class="listdiv">
	<ul>

	<?php
		$kugiri='<li><span class="square">◆Post date&ensp; : &ensp;Species name&ensp; : &ensp;Scientific name&ensp; : &ensp;upload images&ensp; : &ensp;Date picture taken</span></li>';

		$per_page=120;//1ページの表示投稿数

//全投稿数を得るためのsqlの組み立て
$sql = <<< HERE
SELECT COUNT(a.ID) FROM $wpdb->posts a
WHERE a.post_type = 'post'
AND a.post_status = 'publish'
HERE;

		//sqlを実行して$pcountに全投稿数を得る
		$pcount=$wpdb->get_var($sql);

		// 投稿の数から全ページ数を求める
		$page_counts=ceil($pcount / $per_page);
		// URLからページ番号を得る
		$page_no=intval($wp_query->get('paged'));
		if ($page_no < 1) {
			$page_no = 1;
		}elseif($page_no > $page_counts) {
			$page_no = $page_counts;
		}
		// オフセットを求める
		$offset = ($page_no - 1) * $per_page;

//必要なデータを得るためのsqlの組み立て
$sql=<<<HERE
SELECT a.ID,a.post_date,a.post_title,a.guid FROM $wpdb->posts a
WHERE a.post_type = 'post'
AND a.post_status = 'publish'
ORDER BY a.post_date DESC
LIMIT $offset, $per_page
HERE;

		//sql実行して結果を配列にて取得
		$postids=$wpdb->get_results($sql,ARRAY_N);
		
		$countfor=1;
		foreach($postids as $postid){

			if($countfor%30==1){
				//一定の行数ごとに表題を挿入しています。
				echo $kugiri;
			}

			$pid=$postid[0];//投稿IDを$pidに代入

			echo '<li><a href="'.$postid[3].'" class="listdivmain" title="Go this post page.">'.mb_substr($postid[1],0,10).' : '.$postid[2].'</a> : ';

			//投稿IDからカスタムフィールドの値を取得
			$custdata=get_post_custom($pid);
			$pastdata=$custdata["dataID"];
			$dpicdt=end($custdata["撮影日時"]);
			if($pastdata[0]==0){
				$spname=end($custdata["英名"]);
				$spname=str_replace(" ","_",strtolower($spname));
				$biname=end($custdata["学名"]);
			}else{
				$custdata=get_post_custom($pastdata[0]);
				$spname=end($custdata["英名"]);
				$spname=str_replace(" ","_",strtolower($spname));
				$biname=end($custdata["学名"]);
			}
			echo "<a href=\"JavaScript:sendtagslug('x".$spname."')\" class=\"greycolor\" title=\"Go this bird images page.\">".$biname."</a>";

//投稿に属する画像の数を得るためのsqlの組み立て
$sql = <<< HERE
SELECT COUNT(a.ID) FROM $wpdb->posts a
WHERE a.post_parent = ${pid}
AND a.post_mime_type LIKE 'image/%'
AND a.post_type = 'attachment'
HERE;

			$numatch=$wpdb->get_var($sql);

			echo ' : '.$numatch;
			echo " : <span class=\"smallblue\">".$dpicdt."</span>";
			echo "</li>";
			$countfor++;//リストの行数を数えるカウンター
		}
	?>
	</ul>
</div>

これにした場合のページネーションは前述の本、「PHPによるWordPressカスタマイズブック―3.x対応」の方法をそのまま活用させていただきました。
get_pagenum_link()を使用して各ページへのリンクを表示させます。
get_pagenum_link(1)のように引数に1を与えれば1ページ目、現在のページ番号を持つ変数$page_noを使ってget_pagenum_link($page_no+1)のようにすれば次のページへのリンクが得られます。
後は、1ページ目や最後のページの時に矢印を表示させるためのif文をつけたり、中間ページ用のリンクをfor文のループで作るだけですね。尚、最後のページ番号は全ページ数とおなじですから変数$page_countsで既に得ています。

Leave a Reply!

JavaScript is necessary to send a comment.
You can edit and delete your comment if you input a edit key.
Edit key is necessary for attesting you when you edit and delete it.
The tag of HTML cannot be used in comment.
When you comment for the first time, it is displayed after the approval of the administrator.
Because I cannot speak English so much, it takes time to answer.
Required fields are marked *.

※Please enter more than 5 characters only alphabets.
※Edit or delete are possible for 2000 days after approval.

*

♠Simplistic Comment User Editable v4.0

♠When visitors leave comments on the site this site collect the data shown in the comments form, and also the visitor’s IP address and browser user agent string to help spam detection.
♠This site does not use cookie when visitors leave comments and commenter edit comment.
♠This site uses Akismet to reduce spam. Learn how your comment data is processed.

Comments feed

Trackback URL : https://strix.main.jp/wp-trackback.php?p=28370

Sanbanse Funabashi
2011.01.01 sunrise

Top

スクロールさせるか画像をクリックすると元に戻ります。