Wonderful! WordPress

全てのアップ画像によるスライドショーのjQuery

Page No.1

この記事は公開または最後に更新されてから1795日が経過しています。情報が古くなっている可能性があるのでご注意下さい。

投稿でアップロードした全ての画像によるスライドショーのjavascript は、『スライドショー』で作っています。
今回はそれをjQuery で作り直したというだけのこと。
機能的には全く同じ。
*2016/10/05に改めて見直して改善したのでこの記事も全て書き直しています。

画像の数が少なければあらかじめjavascript の中に設定しておけばなんてことはなく簡単なことなのではありますが、その数が3万枚、4万枚ともなって、しかも毎日のようにアップロードしているとなると、とてもそんなことはやっていられないのです。そこでなんとか考えた手段。
投稿が保存される時にアクションフック save_postにて、php で画像アップロードフォルダにある画像のリストをxml で作成しておいて、javascript(jQuery)でそのxml ファイルを読み込んで画像ファイルの情報を得ようという考えです。

画像ファイルのリストを作成するにあたり、アップロードしてある全ての画像の情報を取得する場合には、WordPress は介さずに、php によってアップロードディレクトリをスキャンする方法か、もしくはSQLにてデータベースに登録してあるデータを取得する方法を使用しています。本来はget_posts() で得る方法が正当なのでしょうが、この場合欲しい情報は画像ファイルのurl だけに限られているので、取得するデータをSQLにて限定した方が、画像の枚数が大量にあった場合、パフォーマンス、そして負荷の面でも有効的なのではと考えました。そして、アップロードディレクトリをスキャンする方法では、投稿にアップロードしていない、たとえばヘッダー用の画像などもリストに含まれるので、どちらを使用するかは何が必要かで選択することになります。
一度、全ての画像の情報を取得してリストを作ってしまえば、あとは投稿する都度に、その投稿でアップロードした分の情報を足していくだけのことで済みます。

アクションフック save_postのパラメータで得られる$post から投稿の内容を取得して、get_children()を使用すれば、投稿に張り付けられたものもそうでないものも、その投稿にアップロードされたすべての画像の情報を取得することができるので、その方法を使用しています。
get_children()に関しては、«get_children()で投稿にアップロードした画像を全て表示»にて書いています。

これとは別に他の手段として使っているのが、サイト読み込みのテンプレートの始めの部分で、SQL によってあらかじめデータベースから200ほどの画像のurl を読み出し、それをつなげて一つの文字列とし、html の隠し要素にその文字列を仕込んでおいてjavascript から読み出して使うということ。200の画像を全部表示したらそのページを再読み込みさせることで、また新しい画像群の情報を得て、続けて表示しつづけさせるという具合です。まぁ、それはおいといて・・・。

・・・

その画像のリストであるxml を作成するためのphp は前述の『スライドショー』のページにあるのですが・・・。
ところで、今回のことで改めてそのxml ファイルを見てみると、なんということか2.6MB にもなってしまっている。これはあまりにも大きくなりすぎてよろしくないということで、リストのダイエットをすることに。
そのxml は以下のようになっているのですが。

<?xml version="1.0" encoding="UTF-8" ?>
<files>
<imgs>./wp-content/uploads/2011/10/0911085193.jpg</imgs>
<imgs>./wp-content/uploads/2011/10/0911085212.jpg</imgs>
<imgs>./wp-content/uploads/2011/10/0911085214.jpg</imgs>
<imgs>./wp-content/uploads/2011/10/0911085219.jpg</imgs>
</files>
XML
CopyExpand

当たり前であり変わる事の無い”./wp-content/uploads/20” と”.jpg” の文字列はいらないし、xml のタグもかなり無駄。別にファイルの形式をxml にこだわる必要もありません。改行も無くしそれぞれのファイル名は記号ひとつで分けておいて、javascript で使うときにはsplit で配列にすればよいと。始めからそうすればよかったのですがね・・・。
と、残っているのはファイルを指定するために最低限必要な文字列 ”11/10/0911085193” であるわけですが、年と月の二けたの数字も工夫できそうです。年の数字もとりあえずは25ぐらいまであれば当分は気にする必要もないので、アルファベットで置き換えてしまえば/も含めて6文字を2文字に減らせます。

ということで、書き直した画像リスト作成のphp
アップロードディレクトリを全てスキャンする処理とSQLによってデータベースにあるデータを取得する処理も含めています。これは画像のリストファイルを改めて作り直したいときなどのために、画像リストファイルが存在しない時に動くようにしています。
尚、6行目~8行目の自動保存の判別は以前に使用していたもの。”if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )” の条件式はcodex の『関数リファレンス/add meta box 』のページの中にも記載されている自動保存ルーチンかどうかをチェックする方法。実際の動作の詳細を実験してみると、機能しているもののこちらの意図するところには完全ではなく、投稿のpost_status を使用する方法に変更しました。

尚、ファイル操作においては、WP_filesystemcodexにあったまんまを使用しています。WP_filesystemに関してはこちら→«WordPress のFilesystemとかAjaxとか»を。

<?php
	function imagefile_to_xml( $post_id, $post, $update ){
		$ptype = $post->post_status;
	
		//自動保存なら無効
		/*if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
			return;
		}*/

		// post_statusがpublishかfutureの時だけ起動
		if ( 'publish' === $ptype or 'future' === $ptype ) {

			$nyear = date( 'Y' );
			$nmonth = date( 'm' );

			// 年と月の二けたの数字をアルファベットに置き換えるための配列
			$numary = array(
				'01' => 'A',
				'02' => 'B',
				'03' => 'C',
				'04' => 'D',
				'05' => 'E',
				'06' => 'F',
				'07' => 'G',
				'08' => 'H',
				'09' => 'I',
				'10' => 'J',
				'11' => 'K',
				'12' => 'L',
				'13' => 'M',
				'14' => 'N',
				'15' => 'O',
				'16' => 'P',
				'17' => 'Q',
				'18' => 'R',
				'19' => 'S',
				'20' => 'T',
				'21' => 'U',
				'22' => 'V',
				'23' => 'W',
				'24' => 'X',
				'25' => 'Y',
			 );

			// WP_filesystemはcodexにあったままを使用
			$access_type = get_filesystem_method();
			if ( $access_type === 'direct' ) {
				// request_filesystem_credentials() を安全に実行することができますので、URLを渡しても問題ありません
				$creds = request_filesystem_credentials( site_url() . '/wp-admin/', '', false, false, array() );

				// API の初期化
				if ( ! WP_Filesystem( $creds ) ) {
					// 問題が発生すれば処理を抜ける
					return false;
				}

				global $wp_filesystem;
				// ファイルの操作を以下に実行する

				$i = 0;
				$fcount = 0;
				$newary = array();
				$tmpstr = array();

				// get_template_directory()は、
				// /var/www/html/example/wp-content/themes/twentyten/等のテーマディレクトリのフルパス
				//画像リストファイルの指定
				$xmlfile = get_template_directory() . '/imgs.php';

				// アップロードディレクトを取得
				// $upload_dir['baseurl']でhttps://localhost/example/wp-content/uploadsのアップロードディレクトリのurl
				// $upload_dir['basedir']で/var/www/html/example/wp-content/uploadsのアップロードディレクトリのフルパス
				$upload_dir = wp_upload_dir();

				// 画像リストファイルが既に存在する場合はその投稿でアップロードされた画像のみを取得してリストに追加
				if ( $wp_filesystem->exists( $xmlfile ) ) {
					$attachments = get_children( array( 'post_type' => 'attachment', 'post_mime_type' => 'image', 'post_parent' => $post->ID, 'orderby' => 'menu_order' ) );
					if ( ! empty( $attachments ) ) {
						foreach ( $attachments as $attachment ) {
							$image = wp_get_attachment_image_src( $attachment->ID, 'full' );
							// アップロードディレクトの文字列を取得してファイルのパスから消去
							$uploadurl = $upload_dir['baseurl'] . '/20';
					 		$tmpurl = str_replace( array( $uploadurl, '.jpg' ), '', $image[0] );
					 		// 年と月の数字をアルファベットに変換
					 		$tmpurl = explode( '/', $tmpurl );
					 		$tmpstr[] = $numary[ $tmpurl[0] ] . $numary[ $tmpurl[1] ] . $tmpurl[2];
						}

						// 画像リストファイルのデータを取得
						$orilist = $wp_filesystem->get_contents( $xmlfile );
						// データは,区切りになっているので配列に分割
						$oriary = explode( ',', $orilist );
						// 画像リストに新リストを結合させて、重複したデータを消去
						$newary = array_merge( $oriary, $tmpstr );
						$newary = array_unique( $newary );
					}

				// 画像リストファイルが存在しない時は全ての画像のデータを取得
				} else {
					/*
					// アップロードディレクトリを全てスキャンする場合はこれを使用
					// /var/www/html/example/wp-content/uploads/等のアップロードディレクトリのフルパス
					$dirname = $upload_dir['basedir'] . '/';

					if ( $wp_filesystem->exists( $dirname ) ) {
						// アップロードディレクトリをスキャン
						$filearrayasc = scandir( $dirname );
						foreach ( $filearrayasc as $val ) {
							if ( false !== strpos( $val, '20' ) ) {
								// 年から20を消去してアルファベットに変換
								$ynum = str_replace( '20', '', $val );
								$ynum = $numary[ $ynum ];
								$cdir = $dirname . $val . '/';
								$cfile = scandir( $cdir );
								foreach ( $cfile as $data ) {
									if( '.' !== $data and '..' !== $data ) {
										// 月をアルファベットに変換
										$mnum = $numary[ $data ];
										$gcdir = $cdir . $data . '/';
										$gcfile = scandir( $gcdir );
										foreach ( $gcfile as $fname ) {
											if ( '.' !== $fname and '..' !== $fname and false === strpos( $fname, 'x' ) ) {
												$imgname = $ynum . $mnum . str_replace( '.jpg', '', $fname );
												$newary[] = $imgname;
												++$fcount;
											}
										}
									}
								}
							}
						}
					}*/

					// wordpressのデータベースにある画像ファイルのデータを使用する場合はこちらを使用
					global $wpdb;
					// 画像を読み込む
					$sql = <<< HERE
					SELECT a.guid FROM $wpdb->posts a, $wpdb->posts p
					WHERE a.post_parent = p.ID
					AND a.post_mime_type LIKE 'image/%'
					AND a.post_type = 'attachment'
					ORDER BY a.ID
HERE;

					$attachments = $wpdb->get_results( $sql );
					$uploadurl = $upload_dir['baseurl'] . '/20';
					foreach ( $attachments as $val ) {
						// アップロードディレクトの文字列を取得してファイルのパスから消去
				 		$tmpurl = str_replace( array( $uploadurl, '.jpg' ), '', $val->guid );
				 		// 年と月の数字をアルファベットに変換
				 		$tmpurl = explode( '/', $tmpurl );
				 		$newary[] = $numary[ $tmpurl[0] ] . $numary[ $tmpurl[1] ] . $tmpurl[2];
					}
				}

				// 配列を,で区切った文字列に変換
				if ( $newary ) {
					$outary = '';
					foreach( $newary as $val ) {
						if ( strlen( $val ) > 6 ) {
							$outary .= $val . ',';
						}
					}

					$wp_filesystem->put_contents( $xmlfile, $outary, FS_CHMOD_FILE);
				}
			}
		}
	}

	// 投稿タイプが” post ” の時だけ起動させたいので、post type 指定限定型のフック、save_post_{$post->post_type}を使用。
	add_action( 'save_post_post', 'imagefile_to_xml', 10, 3 );

	// 投稿のステイタスが変更されるときのフックを利用してフックをremoveするための関数
	function on_future_publish_post( $post ) {
		remove_action( 'save_post_post', 'imagefile_to_xml' );
	}

	// 投稿のステイタスがfuture→publishに変更されるときは処理をキャンセル
	add_action(  'future_to_publish',  'on_future_publish_post', 10, 1 );
	// 同じく投稿のステイタスがpending(レビュー待ち)→publishに変更されるときは処理をキャンセル
	add_action(  'pending_to_future',  'on_future_publish_post', 10, 1 );
?>
PHP
CopyExpand

functions.php に記述し、投稿が保存される時のフックで投稿タイプが” post ” の時だけ有効になる、post type 指定限定型のフック、save_post_{$post->post_type} を使用。
そして、同じ投稿に対して投稿ステイタスがpublish とfuture の時で何度も動かす必要はないので、投稿のステイタスが変更されるときのフックを利用して、投稿のステイタスがfuture → publish に変更されるときとpending(レビュー待ち) → publish に変更されるときにフックをremoveしています。
そのsave_post フックに関しては、«投稿の自動保存(Autosave)の判別について»にていろいろやっていますのでそちらをご覧ください。
出来た画像リストは以下のように。

KJ0911085193,KJ0911085212,KJ0911085214,KJ0911085219,KJ0911085233,~
XML
CopyExpand

改行も入っていないので見ずらいですが、これにてサイズは600KB まで減らすことができました。2.6MB あったので 1/4 以下になったということです。効果は歴然でスライドショーの起動が速くなったのを体感できました。
一応、実際に画像が表示される時に土台となる隠しdivのhtml を載せておくと。
4行目の タグが実際に画像を表示するためのタグになるわけですが、一応、透明の画像を指定しています。実はこのsrc の指定からjQueryで使用するアップロードディレクトリのurl を抜き出して使うという事をしています。jQueryのなかで、テーマとかアップロードのディレクトリを得る方法はいくつかありますが、とりあえずここから得ているということなので、これはこれでちょっと重要な部分なのです。


<div id="imageframe">
	<p id="explain">画像をクリックすれば元に戻ります。</p>
	<div id="popup">
		<img src="<?php bloginfo('template_url'); ?>/clear.png" id="upimage" alt="" />
	</div>
	<div id="slidestop">
		<div id="slidecount"></div>
		<div id="slidecom">
			<span id="stopslide">stop slide show</span>&emsp;&emsp;
			<span id="pauseslide">pause</span>&emsp;&emsp;
			<span id="sldrestart">restart</span>&emsp;&emsp;
			<span id="backslide">stop & back</span>&emsp;&emsp;
			<div id="slctdown"></div>
		</div>
	</div>
	<div id="rightarrow">&raquo;</div>
	<div id="leftarrow">&laquo;</div>
</div>
PHP
CopyExpand

そしていよいよ本題のjQueryとなります。
まずは変数の宣言とxml ファイルを読み込んでスライドショーを始める部分。

jQuery( function() {
	var stx_sldshw = {};
		stx_sldshw.img01 = new Image();//表示する画像
		stx_sldshw.nextimg = new Image();// 次の画像のurlを入れておくための変数
		stx_sldshw.backnextimg = new Image();// 逆順表示のとき画像のurlを入れておくための変数
		stx_sldshw.imgsrc = '';//画像配列から取得した画像のurl
		stx_sldshw.imagesary = [];//ファイルから取得した画像のurlを格納する配列
		stx_sldshw.tarlist = [];//既に表示した画像の再表示を避けるための配列のキーを格納する配列
		stx_sldshw.pastimg = [];//既に表示した画像のurlを格納する配列、先頭から新しい順
		stx_sldshw.slideID = null;//スライドショーループid
		stx_sldshw.callID = null;// 画像ロードで待たされるときのスライドショー呼び出しループid
		stx_sldshw.ctdwID = null;//秒数カウントダウン用ループid
		stx_sldshw.callctdwID = null;//秒数カウントダウン用ループ呼びだしid
		stx_sldshw.sumnum = 0;//表示した画像の合計数
		stx_sldshw.nonenum = 0;//表示する画像の番号を乱数で得るときに、重複した場合にリストの逆順から探す場合のいくつ遡ったかの数
		stx_sldshw.nonestr = '';//nonenumを表示する場合のフラグ件つなぎ文字
		stx_sldshw.timenum = 0;//スライドショーの画像を表示する間隔
		stx_sldshw.tarnum = 0;//乱数で取得する表示する画像のキーナンバー
		stx_sldshw.backnum = 1;//画像を遡って表示する場合の指示番号
		stx_sldshw.sldflg = 0;//スライドショーが動いているかのフラグ、未使用
		stx_sldshw.hzm_rasio = 0.95;
		stx_sldshw.wzm_rasio = 0.8;
		stx_sldshw.is_file_comp = 0;
		stx_sldshw.enloadflg = 0;// 画像がロードされて表示されたか否かのフラグ
		stx_sldshw.imagescount = 0;
		stx_sldshw.intarvalnum = 0;
		stx_sldshw.ctnum = 0;
		stx_sldshw.uploaddir = './wp-content/uploads/20';
		stx_sldshw.numary = {
			'A': '01/',
			'B': '02/',
			'C': '03/',
			'D': '04/',
			'E': '05/',
			'F': '06/',
			'G': '07/',
			'H': '08/',
			'I': '09/',
			'J': '10/',
			'K': '11/',
			'L': '12/',
			'M': '13/',
			'N': '14/',
			'O': '15/',
			'P': '16/',
			'Q': '17/',
			'R': '18/',
			'S': '19/',
			'T': '20/',
			'U': '21/',
			'V': '22/',
			'W': '23/',
			'X': '24/',
			'Y': '25/'
		 };

	// id=upimageのimgタグのsrcからアップロードディレクトリのurlを取得
	if ( jQuery( '#upimage' ).length ) {
		stx_sldshw.uploaddir = jQuery( '#upimage' ).attr( 'src' );// https://localhost/wp/wp-content/themes/sanbanze/clear.png
		stx_sldshw.uploaddir = stx_sldshw.uploaddir.substr( 0, stx_sldshw.uploaddir.indexOf( 'theme' ) ) + 'uploads/20';// https://localhost/wp/wp-content/uploads/20
	}

	// 画像リストファイルを読み込んで起動する時のスタート関数
	stx_sldshw.slidestart = function( file ) {
	
		jQuery( '#slctdown' ).text( 'Now loading and setting!' );
	
		if ( -1 !== file.indexOf( 'imgs.php' ) ) {
			stx_sldshw.is_file_comp = 1;
		}

		// 指定されたファイルをgetで読み込み
		jQuery.get( file, function( data ) {
			// ファイルから読み込んだデータを配列にする関数を呼び出す
			stx_sldshw.datatreat( data );
			// 一枚目の画像を表示してループを呼び出す関数
			stx_sldshw.firstimage();
		});
	}

	// Ajaxにより画像リストを取得して起動する時のスタート関数
	stx_sldshw.slidestart_nofile = function( file, tag ) {
	
		jQuery( '#slctdown' ).text( 'Now loading and setting!' );

		// Ajax ( post )でデータを取得
		// この場合の file はwordpressで指定されている'/wp-admin/admin-ajax.php'
		// パラメータ'action'で指定する'get_imgs_list'はfunctions.phpにおいてアクションフック名に指定する部分
		// パラメータ'tag'は呼び出すphp関数においてデータを絞り込むのに必要なデータで、このように独自のパラメータ等も渡すことができる
		jQuery.post(
			file,
			{ 'action' : 'get_imgs_list', 'tag' : tag},
			function( data, status ) {
				// Ajaxから取得したデータを配列にする関数を呼び出す
				stx_sldshw.datatreat( data );
				// 一枚目の画像を表示してループを呼び出す関数
				stx_sldshw.firstimage();
			}
		);
	}

	// 渡された,区切りのデータを配列にする関数
	stx_sldshw.datatreat = function( datastr ) {
		var i =0,
			j = 0,
			arrdata,// 読み込んだリストを一時的に入れる配列
			arrdataleng;// その配列の個数
	
		arrdata = datastr.split( ',' );
		arrdataleng = arrdata.length;
		for ( i = 0; i < arrdataleng; i++ ) {
			if ( arrdata[ i ].length > 4 ) {
				stx_sldshw.imagesary[ j ] = arrdata[ i ];
				stx_sldshw.tarlist[ j ] = 1;
				++j;
			}
		}
		stx_sldshw.imagescount = stx_sldshw.imagesary.length;
	}

	// 初期化と一枚目の画像を指定してループ関数を呼び出す関数
	stx_sldshw.firstimage = function() {
		var rand;
	
		// 画像を切り替える際にだぶらせて表示させるためのゴースト画像を表示するための<img>タグの登録
		if ( ! jQuery( '#subupimage' ).length ) {
			jQuery( '#popup' ).append( '<img src="" id="subupimage" />' );
			jQuery( '#subupimage' ).css( {
				position: 'absolute',
				top: '2px',
				left: '50%',
				zIndex: '1',
			} );
		}

		//スライドショーのインターバルをページのinput要素から取得して設定
		stx_sldshw.timenum = parseInt( jQuery( '#intnum' ).val() );
		if ( stx_sldshw.timenum < 4 || stx_sldshw.timenum > 50 ) {
			stx_sldshw.timenum = 10;
		}
		stx_sldshw.intarvalnum = stx_sldshw.timenum * 1000;

		// 乱数を発生させる
		rand = Math.floor( Math.random() * 100000000 );
		// その乱数を画像の数で割った余りを表示する画像の番号にする
		stx_sldshw.tarnum = rand % stx_sldshw.imagesary.length;
		// 一度使った番号はフラグを-1に設定
		stx_sldshw.tarlist.splice( stx_sldshw.tarnum, 1, -1 );
		// 表示した画像の番号を配列にストック(逆順で表示させるため)
		stx_sldshw.pastimg[0] = stx_sldshw.tarnum;

		// 得られた番号により画像の配列から画像の加工前のurlを取得
		stx_sldshw.imgsrc = stx_sldshw.imagesary[ stx_sldshw.tarnum ];
		// アルファベットに置き換えられている場合は年月を元に戻す
		if ( stx_sldshw.is_file_comp ) {
			stx_sldshw.imgsrc = stx_sldshw.numary[ stx_sldshw.imgsrc.substr( 0, 1 ) ] + stx_sldshw.numary[ stx_sldshw.imgsrc.substr( 1, 1 ) ] + stx_sldshw.imgsrc.slice(2);
		}
		stx_sldshw.imgsrc = stx_sldshw.uploaddir + stx_sldshw.imgsrc + '.jpg';// stx_sldshw.uploaddir : /wp-content/uploads/20
		// imageオブジェクトに画像のurlを渡す。多分これで画像の先読みにもなると思われる。あくまで多分。
		stx_sldshw.nextimg.src = stx_sldshw.imgsrc;
	
		jQuery( '#imageframe' ).css( 'visibility', 'visible' );
		jQuery( '#explain' ).css( 'visibility', 'hidden' );
		jQuery( '#slidestop' ).css( 'visibility', 'visible' );
		jQuery( '#rightarrow' ).css( 'visibility', 'hidden' );
		jQuery( '#leftarrow' ).css( 'visibility', 'hidden' );

		// スライドショーのループ関数の呼び出し。
		stx_sldshw.slideshow();
	}
} );
JavaScript
CopyExpand

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

Sanbanse Funabashi
2010.10.24 sunrise

Top

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