Wonderful! WordPress

続、画像の枚数によるタグクラウドの自作

画像の枚数によるタグクラウドの自作」で自作したタグクラウド。「phpのチューニングによるサイト表示速度の改善」の時に既に一度、速度アップのための改良を試みて、一応の結果を得る事が出来ました。

しかし、コードを見ているとまだまだ改良の余地はありそう。
現在のところ、持っている画像の鳥種は200種あまり。
200回あまりSQLによって各鳥種の画像の枚数を問い合わせしています。
日本国内にて見る事ができる鳥種は600種+。
まだまだこれから増える予定なので、増えれば増えるほど処理が重くなっていくわけで(そんなのなんでもあたりまえですが)、このあたりもなんとか少しでも軽いに越したことはない。

あーでもないこーでもないと考えた末に、思いついたのが鳥種と画像の枚数のリストをファイルとしてあらかじめ作っておくというもの。データをファイルで一気に読み込んで取得した方が速いように思えるのです。
なんだかそれだとデータベースを使ってる意義が無いようにも思えるのですが、この際、速くなりそうならとりあえずやってみようと。

鳥種の画像の枚数は、公開待ちの投稿のものの数は入れず、既に公開済みの投稿だけに限りたいので、鳥種の画像枚数リスト(以降、タグリスト)は投稿を公開するときに更新させるようにします。
これは既に「スライドショー」において、画像のurlのxmlリストを更新するときに使っているアクションフック、publish_postを使います。
その画像urlのxmlリストの方は、いまにして思えば投稿を保存するときのアクションフック、save_postを使って動かした方がいいと思い、変更しました。

タグリストの中身は「日本語名:英語名:枚数」と並べただけのシンプルなもの。
ちなみにこの英語名は投稿タグのslugそのもの。
リストの先頭に、最も枚数の多い鳥種をリストしておきます。

Aトウネン:red-necked_stint:828
アオアシシギ:common_greenshank:188
アオゲラ:japanese_green_woodpecker:57
アオサギ:grey_heron:8
アオシギ:solitary_snipe:23
アオジ:black-faced_bunting:83
アオバズク:brown_hawk_owl:99
アオバト:white-bellied_green_pigeon:28
アカアシシギ:common_redshank:137
アカエリヒレアシシギ:red-necked_phalarope:67
		:

最多数の先頭に”A”を付けているのは、新種を追加してソートした時に、先頭に位置させるためです。
で、このリストを更新するコード。
実は掲載してたコードにケアレスなバグがあって2013/6/9に訂正しました。
なんてことはない最高値の鳥種のリスト中の値が更新されないというものでした。
最高値を記録してる先頭の行と2つデータが存在しているので、配列を検索したときに先頭の行がヒットしてその値を更新していたので、リスト中のその鳥の行が更新されていなかったというものです。
explodeでデータをそれぞれの配列に分けて、最高値を得た後でそれぞれの配列から先頭の値を抜いてしまうことで対処しました。
array_shiftはわざわざ変数に入れなくてもいいようにも思ったのですが。

<?php
function update_taglist($post_id){
	//function.php内の関数にてsqlを使う時のお約束
	global $wpdb;

	/*publish_postの引数$post_idから投稿の情報を取得
	post_typeがpostの時だけ作動*/
	$mypost=get_post($post_id);
	$mytype=$mypost->post_type;
	if($mytype=='post'){

		//$post_idから投稿タグを取得
		$tagsinfo=get_the_tags($post_id);
		if(count($tagsinfo)>0){
			$stag_jname=array();
			$stag_ename=array();

			foreach($tagsinfo as $val){
				$stag_jname[]=$val->name;
				$stag_ename[]=$val->slug;
			}

			/*作成するタグリストファイルの指定
			この場合はフルパスでないとダメ(*で省略してあります)*/
			$tagfile='/home/users/***/torilist.php';
			if(file_exists($tagfile)){//ファイルがあるか確認
				$tags_list=array();
				//file関数でファイルを一気に取得
				$tags_list=file($tagfile);
				$engary=array();
				$japary=array();
				$cntary=array();

				foreach($tags_list as $val){
					//リストをexplodeで分割してそれぞれ配列に収める
					list($tmpjp,$tmpen,$tmpnum)=explode(':',$val);
					$engary[]=$tmpen;
					$japary[]=$tmpjp;
					$cntary[]=trim($tmpnum);//末尾の改行を除去
				}
				//リストの1行目には最多数の数
				$maxcount=intval($cntary[0]);
				$dust=array_shift($engary);
				$dust=array_shift($japary);
				$dust=array_shift($cntary);

				$chgflg=0;//リストに変更を加えたかのフラグ
				//投稿タグのそれぞについてslugにてループ
				foreach($stag_ename as $key=>$val){
					$stag_name=$val;
$sql=<<<HERE
SELECT COUNT(a.ID) FROM $wpdb->posts a, $wpdb->posts p, $wpdb->term_relationships r, $wpdb->term_taxonomy x, $wpdb->terms t
WHERE  a.post_parent = p.ID
AND p.ID = r.object_id
AND r.term_taxonomy_id =x.term_taxonomy_id
AND x.term_id=t.term_id
AND a.post_mime_type LIKE 'image/%'
AND a.post_type = 'attachment'
AND p.post_status = 'publish'
AND x.taxonomy='post_tag'
AND t.slug='${stag_name}'
HERE;
					//SQLで投稿タグのslugを使って画像の枚数を取得
					$tag_counter=$wpdb->get_var($sql);
					if($tag_counter>0){
						//現在の鳥のリスト用の文字列作成
						$curbird=$stag_jname[$key].':'.$val.':'.$tag_counter."\n";
						//投稿タグのslugでタグリストに既存か英名配列を検索
						$searchflg=array_search($val,$engary);
						if($searchflg!==false){
							//あれば枚数を比較して、多ければ置換
							if(intval($cntary[$searchflg])<$tag_counter){
								++$searchflg;
								//リストから先頭の値を抜いているので+1しないと元のリストと合わない
								$tags_list[$searchflg]=$curbird;
								$chgflg=1;
							}
						}else{//なければ配列の最後に追加した後ソート
							array_push($tags_list,$curbird);
							asort($tags_list,SORT_STRING);
							$chgflg=1;
						}
						//最多数の比較と必要であれば更新
						if($maxcount<$tag_counter){
							$tags_list[0]='A'.$curbird;
							$chgflg=1;
							$maxcount=$tag_counter;
						}
					}
				}
				//リストに更新があればファイルも更新
				if($chgflg===1){
					file_put_contents($tagfile,$tags_list,LOCK_EX);
				}
			}
		}//b
	}//a
}

add_action('publish_post','update_taglist');
?>

じつは、これをテストしている時は気づかずに最後の行のadd_actionをadd_filterでやってました。
でも、不思議とちゃんと作動してた。まっいいか!
前述しましたが、これを考えている時にスライドショー用の画像のurlのリストであるxmlを更新するのはsave_postに変更しました。
で、その時に同じく思いついたのは、「カスタム分類による画像個別の分類」の項で、カスタム分類において分類の対象をattachmentに指定した場合、その分類のcountが記事の保存や公開の際には更新されず、処理の仕方がわからずにそのままになっていた件。
これもこのsave_postを使えば出来るのではないかと。
結果、その件も解決していますので、「カスタム分類による画像個別の分類」のページも更新しています。
そして改良したタグクラウドを出力する関数。

<?php
function createtagscloud($openum,$eng){
	$opeflg=0;
	$tag_data=array();
	$japary=array();
	$cntary=array();
	$tag_num=0;
	$maxcount=0;

	//ファイルが存在するとき
	$tagfile='./wp-content/themes/first/torilist.php';
	if(file_exists($tagfile)){
		$tags_names=array();
		//ファイルをfile関数で一気に読み込んで
		$tags_names=file($tagfile);
		//最多数の先頭行を取り除きつつ取得
		$topbird=array_shift($tags_names);
		//explodeで分割しつつ、最多数の数を得ます
		list($topjp,$topen,$maxcount)=explode(':',$topbird);
		$maxcount=intval(trim($maxcount));

		if($eng==0){//日本語名表記の時だけその後の処理が違う
			$opeflg=1;
		}else{
			/*英語名表記の場合は英語名でのソートが必要なため
			先にそれぞれ分割して配列にする*/
			foreach($tags_names as $val){
				list($tmpjp,$tmpen,$tmpnum)=explode(':',$val);
				$tag_data[]=$tmpen;
				$japary[]=$tmpjp;
				$cntary[]=trim($tmpnum);
			}
		}
	}else{//無い時は今まで同様の処理
		global $wpdb; 
		if($eng==0){
			$tags_names=get_tags('orderby=name');
		}else{
			$tags_names=get_tags('orderby=slug');
		}
		
		foreach($tags_names as $list){
			$stag_name=$list->slug;
$sql=<<<HERE
SELECT COUNT(a.ID) FROM $wpdb->posts a, $wpdb->posts p, $wpdb->term_relationships r, $wpdb->term_taxonomy x, $wpdb->terms t
WHERE  a.post_parent = p.ID
AND p.ID = r.object_id
AND r.term_taxonomy_id =x.term_taxonomy_id
AND x.term_id=t.term_id
AND a.post_mime_type LIKE 'image/%'
AND a.post_type = 'attachment'
AND p.post_status = 'publish'
AND x.taxonomy='post_tag'
AND t.slug='${stag_name}'
HERE;
			$tag_counter=$wpdb->get_var($sql);
			$tag_data[]=$stag_name;
			$japary[]=$list->name;
			$cntary[]=$tag_counter;

			if($maxcount<$tag_counter){
				$maxcount=$tag_counter;
			}
		}
	}

	if($maxcount<10){
		$maxcount=10;
	}else{
		$maxcount=ceil($maxcount/10)*10-480;
	}
	$d1=floor($maxcount*0.1);
	$d2=floor($maxcount*0.2);
	$d3=floor($maxcount*0.3);
	$d4=floor($maxcount*0.4);
	$d5=floor($maxcount*0.5);
	$d8=floor($maxcount*0.75);
	$d9=floor(($maxcount+100)*0.9);

	if($eng==1){//英語名表記の時は英語名でソート
		asort($tag_data,SORT_STRING);
		echo '<ul id="engtags">';
	}

	if($opeflg===1){//日本語名表記の時だけは元のデータがオブジェクト
		foreach($tags_names as $list){
			list($tmpjp,$tmpen,$countval)=explode(':',$list);
			$countval=trim($countval);
			$countint=intval($countval);
			if($countint==0){
				$tag_num=8;
			}elseif($countint<=8){
				$tag_num=0;
			}elseif($countint<=$d1){
				$tag_num=1;
			}elseif($countint<=$d2){
				$tag_num=2;
			}elseif($countint<=$d3){
				$tag_num=3;
			}elseif($countint<=$d4){
				$tag_num=4;
			}elseif($countint<=$d5){
				$tag_num=5;
			}elseif($countint<=$d8){
				$tag_num=6;
			}elseif($countint<=$d9){
				$tag_num=7;
			}else{
				$tag_num=9;
			}
			if($openum==0){
				echo '<a href="https://strix.main.jp/?tag='.$tmpen.'" class="imgtags'.$tag_num.'" title="'.$countval.'枚">'.$tmpjp.'</a>&ensp;';
			}else{
				echo "<a href=\"JavaScript:sendtagslug('x".$tmpen."')\" class=\"imgtags".$tag_num."\" title=\"".$countval."枚\">".$tmpjp."</a>&ensp;";
			}
		}
	}else{//こちらはデータが配列になっている
		foreach($tag_data as $key=>$val){
			$countval=$cntary[$key];
			$countint=intval($countval);
			if($countint==0){
				$tag_num=8;
			}elseif($countint<=8){
				$tag_num=0;
			}elseif($countint<=$d1){
				$tag_num=1;
			}elseif($countint<=$d2){
				$tag_num=2;
			}elseif($countint<=$d3){
				$tag_num=3;
			}elseif($countint<=$d4){
				$tag_num=4;
			}elseif($countint<=$d5){
				$tag_num=5;
			}elseif($countint<=$d8){
				$tag_num=6;
			}elseif($countint<=$d9){
				$tag_num=7;
			}else{
				$tag_num=9;
			}
			if($openum==0){
				if($eng==0){
					echo '<a href="https://strix.main.jp/?tag='.$val.'" class="imgtags'.$tag_num.'" title="'.$countval.'枚">'.$japary[$key].'</a>&ensp;';
				}else{
					$engname=ucwords(strtr($val,'_',' '));
					echo '<li><a href="https://strix.main.jp/?tag='.$val.'" title="'.$countval.'pieces"><span class="imgtags'.$tag_num.' eimgtag">'.$engname.'</span></a></li>';
				}
			}else{
				if($eng==0){
					echo "<a href=\"JavaScript:sendtagslug('x".$val."')\" class=\"imgtags".$tag_num."\" title=\"".$countval."枚\">".$japary[$key]."</a>&ensp;";
				}else{
					$engname=ucwords(strtr($val,'_',' '));
					echo "<li><a href=\"JavaScript:sendtagslug('x".$val."')\" title=\"".$countval."pieces\"><span class=\"imgtags".$tag_num." eimgtag\">".$engname."</span></a></li>";
				}
			}
		}
	}
	if($eng==1){
		echo '</ul>';
	}
}
?>

随分、長くなってしまいました。
最後の出力する部分が、ファイルを読み込んだ時の日本語表記の場合とそれ以外とで別にしてしまったのが原因なのですが、これ以外にやりようが思いつかなかった。
結果、これによる効果はというと、やはり体感的にも表示される秒数の見たところの平均的な感じでも速くなっていると実感しています。
改良前は最多数を得るためにループを2度回さなくてはいけなかったのが、あらかじめ分かっているので1度で済むことと、それぞれの枚数を取得するためのSQLの問い合わせをしなくて済むことが効果的と思えます。
今回の改良でも良い結果を得る事が出来ました。
でも、まだ、やれることはありそうです。

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=33895

Sanbanse Funabashi
2011.01.01 sunrise

Top

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