Page No.1

ちょっと自虐ネタなんぞをぶつぶつと・・・。
汎用のテーマを作っていたりしたのです。
好みでいろいろと設定できるようにオプションを設けて、それを管理画面から設定できるようにと。
前に作った、背景画像が一定時間で切り替わっていく日めくりカレンダーなどもくっつけてみたりして。
その背景画像を好きなように追加できるように、画像のリストを作ってそれをjavascriptで読んで切り替えていくようにと。
いえいえ、テーマのディレクトリに登録するなんてことは考えていなくて、なるべく機能を盛り込んだものをという考えです。
で、その背景画像を追加したときなどに、画像のリストを作るプログラムを管理画面のオプション設定画面から動かせるようにAjax などを使っていたのです。
オプションの設定画面から動かすjavascriptなので、phpで書いてページにprint out したjavascript ということになります。
そのオプション設定ページに表示させるためのhtmlをoutput するための関数などを以下に。これはテーマのオプションを読み込んだり設定したりするクラスの中にある関数です。途中省略してます。肝心なのは最後のjavascript の部分だけではあります。管理画面の中なのでjQuery が使えるのです。

<?php
	public function sbzfb_page_output() {
?>
		<div class="wrap">
			<h2>Sanbanze funabashi Theme</h2>
			<h3>&laquo; Option setting &raquo; </h3>
			<form method="post" action="options.php">
<?php
			settings_fields( 'sbzfb-settings-group' );
			do_settings_sections( 'sbzfb-settings-group' );
?>
			<table class="form-table" style="color:blue;border:dotted 1px blue;">
				<tr valign="top">
					<td>authors_ip</td>
					<td><input type="text" name="sanbanze_fb_options[authors_ip]" value="<?php echo esc_attr( $this->ret_option['authors_ip'] ); ?>" maxlength="15"></td>
					<td>* <?php _e( 'Input of the authors\'s ip address. Empty is disable to save access log.Now your ip is →', $this->domain ); ?><?php echo $ipadrs; ?></td>
				</tr>
				...
				...途中省略
				...
			<tr><td colspan="3" style="color:green;">***** Sidebar settings *****</td></tr>
<?php
				$j = 1;
				foreach( $optkey as $key=>$val ) {
					if ( $key >= 23 and $key <= 30 ) {
						echo '<tr valign="top">';
						echo '<td>' . $val . '</td><td><select name="sanbanze_fb_options[' . $val . ']">';
						$selected = array( '', '', '', '', '', '', '', '', '' );
						$selectvalue = intval( $optval[ $key ] );
						if ( $selectvalue >= 0 and $selectvalue <= 8 ) {
							$selected[ $selectvalue ] = ' selected';
						} else {
							$selected[ $j ] = ' selected';
						}
						++$j;
						for( $i = 0; $i <= 8; ++$i ) {
							$labelstr = ( 0 === $i ? __( 'disable', $this->domain ) : strval( $i ) );
							echo '<option value="' . $i . '"' . $selected[ $i ] . '>' . $labelstr . '</option>';
						}
						echo '</select></td><td>* ' . __( $exp[ $key ], $this->domain ) . "</td></tr>\n";
						if ( 'show_daycalendar' === $val and '0' !== $optval[ $key ] ) {
							echo '<tr><td></td><td><span id="makefacelist" style="display:block;padding:3px;text-align:center;border:solid 1px grey;border-radius:5px;">click make face-image list file</span></td><td></td></tr>';
						}
					}
				}
?>
			<tr><td colspan="3" style="color:green;">***** ***** ***** ***** ***** *****</td></tr>
				...
				...
				...
			</table>
			<?php submit_button(); ?>
			</form>
		</div>
		<script type="text/javascript">
			jQuery( function() {
				jQuery( '#makefacelist' ).click( function() {
					jQuery( this ).text( 'now making!' );
					var facelistmakeurl = '<?php echo get_template_directory_uri(); ?>/todaycal/face_list_make.php';
					var strsends = '<?php echo $this->mytoken; ?>';
					jQuery.post( facelistmakeurl,
						{ sbztarget:strsends },// ワンタイムチケット
						function( data, status ) {
							jQuery( '#makefacelist' ).text( data );
						}
					);
				});
			});
		</script>
<?php
	}
?>
PHP
CopyExpand

61~66行目が肝心のAjax の部分です。そこだけでいいんでないの?そうですね・・・ついつい。
実はこの時はまだ知らなかったのでWordPress 推奨のAjax の作法に基づいたやりかたではありません。リクエストを送信するphpファイルを別途用意してという普通のやりかたでじたばたしてました。なんてことだっ!ってことでそのphpファイルのface_list_make.php。

<?php
	session_start();
	$pstoken = '---';
	$sstoken = '***';
	if ( isset( $_POST['sbztarget'] ) ) {
		$pstoken = $_POST['sbztarget'];
	}
	if ( isset( $_SESSION['sbztoken'] ) ) {
		$sstoken = $_SESSION['sbztoken'];
	}

	if ( $pstoken === $sstoken ) {
		$tmpstr = '';
		$tmpary = array();
		$xmlfile='./face_list.php';

		$dirname='./face/';

		if ( file_exists( $dirname ) ) {
			$filearrayasc = scandir( $dirname );
	
			foreach ( $filearrayasc as $val ) {
				if ( '.' !== $val and '..' !== $val ) {
					$tmpary[] = $val;
					$tmpstr .= str_replace( '.jpg', '', $val ) . ',';
				}
			}
	
			$result = file_put_contents( $xmlfile, trim( $tmpstr, ',' ), LOCK_EX );
			if ( $result ) {
				echo 'Success! ' . count( $tmpary ) . ' files in list';
			} else {
				echo 'Something Error!';
			}
		} else {
			echo 'directry not exist!';
		}
	} else {
		echo 'no admit!';
	}
?>
PHP
CopyExpand

sessionを使用しているのは一応のセキュリティ対策ではあります。いらぬところから動かされないようにとワンタイムチケットなるものです。管理画面の中なのでこれまたcookie は使用できるはずです。チケットの発行はfunctions.php のテーマのオプションを設定するクラスの中に関数を作って、そのクラスを読み込むときに管理画面においてsessionに登録しています。functions.php からではだめだろうかと思いましたが、ちゃんと機能しました。はたして必要でしょうか?

<?php
	public function set_session() {
		session_start();
		$this->mytoken = md5( uniqid( mt_rand(), TRUE ) );
		$_SESSION['sbztoken'] = $this->mytoken;
	}
?>
PHP
CopyExpand

これで機能したのでとりあえずは意図は達成できたのであります。
が、事件はこの後起こってしまったのです。
ネットをうろうろしていたら、「Theme Check 」などというプラグインがあることを知ることになってしまったのであります。
これは楽しそうだと、さっそくチェックさせてみたら、これがまぁ、なんてこったで警告の大行進というような状況で・・・。
その中で、まっさきに目についたのがfopen とか fclose とかfile_put_contents とかファイル操作に関する事。
「警告: ファイル functions.php 内に fopen が見つかりました。 ファイル操作は直接的な PHP ファイルシステムコールの代わりに WP_Filesystem メソッドを使用する必要があります 。 」
とのことです。

なになに?WP_Filesystem とな?そんなのがあるのか?と、いうことになって初めて知ることになった訳です。
しらなかったのね~!あれま~!
ネットでじたばたしてもこれに関しての詳しい情報自体が少ないようです。codex の《ファイルシステムAPI》から引いてみると、

「WordPress自身の自動アップデート機能のために開発されました。ファイルシステムAPIは、ファイルシステム上のローカルファイルを読み書きする機能を、異なるホスティング上でセキュアに行うために抽象化します。
多くのホスティングシステム上のウェブサーバーは、WordPressファイルのオーナーとは異なるユーザーで動いています。この場合、ウェブサーバーからファイルを書き込まれる際に、実際のユーザーアカウントではなく、ウェブサーバーのユーザーアカウントがオーナーのファイルが作られます。このことは、複数のユーザーがひとつのウェブサーバーを共有し異なるサイトが動いている共有ホスティングの場合にセキュリティ上の問題を引き起こします。
WP_Filesystemはファイルを書き込むユーザーが異なるかどうかを判別し、FTPかそれに代わる手段に切り替える機能を有しています。利用可能なPHPライブラリーに依存しますが、WP_FilesystemはFTPを利用するための3つの異なる手段(エクステンション、ソケット、SSH経由)をサポートしており、自動的に最適な手段が選択されます。
この場合、プラグインまたはテーマでユーザーにFTPの認証情報を入力させるコードを実装する必要があります。入力フォームの見た目を統一し、実装を簡単にするための関数が用意されています。 」

と、いうことですな、ふむふむなるほどと。
しかし、実装方法がよくわからないというかむずかしいのですが、codex を見ていくと、「ヒントとトリック」の「WP Filesystem API の方法論」がこの場合にそのまま使用することができそうでした。
で、実はこの時にもしかしたらAjax においても用意されている作法があるのではないか?と、ひらめいたのです。
WordPress での Ajax においては、codex よりもjQuery を使用した場合の解説をしてくれている他の様々なサイトを見た方がわかりやすくて簡単です。

  • WordPress での Ajax においては、javascript からのリクエスト送信先には、「WordPressの管理システムで定義されたURL(bloghome)/wp-admin/admin-ajax.php 」に設定すること。
  • リクエストを受けるphpはfunctions.php の中に関数として記述する。
  • その、functions.php の中に書かれた関数は、リクエストを受け取った時にどのPHP関数を呼び出せばいいのかを、アクションフックにて認識させる。

と、いうことです。
それでは、と、一番上に載せた、オプション設定ページに表示させるためのhtmlをoutput するための関数のなかのAjaxリクエスト送信のjQuery の部分。

<script type="text/javascript">
	jQuery( function() {
		jQuery( '#makefacelist' ).click( function() {
			jQuery( this ).text( 'now making!' );
			jQuery.post( ajaxurl,// wp/wp-admin/admin-ajax.php
				{ 'action' : 'face_list_make', },
				function( data, status ) {
					jQuery( '#makefacelist' ).text( data );
				}
			);
		});
	});
</script>
JavaScript
CopyExpand

見ればわかりますが、POST にての送信です。
リクエスト送信先のurl をajaxurl としています。これは、管理画面においてだけWordPress によってあらかじめ設定されている変数です。管理画面のなかであれば、この変数が使用できます。ちなみに私のローカルな環境においての値は、「wp/wp-admin/admin-ajax.php 」でした。
”action” において設定している文字列は、後述する、php関数をアクションフックで登録する際の、アクションフック名「wp_ajax_{} 」のWp_ajax_につづく{}に指定する部分となります。関数名と同じである必要はありません。
なお、今回はPOST にて書いていますが、ajax で書くなら以下のごとくで当然のことながらほとんど同じようなものです。

jQuery.ajax({
	type: 'POST',
	url: ajaxurl,
	data: {
		'action' : 'face_list_make',
	}
}).done( function( msg ) {
		jQuery( '#makefacelist' ).text( 'ajax-done : ' + msg );
});
JavaScript
CopyExpand

そして、リクエストを受け取る側のfunctions.php に書いたphp関数。
尚、こちらのほうはと言えば、先に書いたWP_Filesystem を、まんまcodex から引っ張り出してきた内容にて適用しています。念のために言っておくと、これはあくまで管理画面内で動かすものであるから、codex そのまんまで使えるということだと。

<?php
	function face_list_make() {
		$tmpstr = '';
		$tmpary = array();

		$temppass = get_template_directory() . '/';
		$xmlfile = $temppass . 'todaycal/face_list.php';
	
		$dirname = $temppass . 'todaycal/face/';
	
		// 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;
			/* ファイルの操作を以下に実行する */
	
			if ( $wp_filesystem->exists( $dirname ) ) {
				$filearrayasc = scandir( $dirname );
				foreach ( $filearrayasc as $val ) {
					if ( '.' !== $val and '..' !== $val ) {
						$tmpary[] = $val;
						$tmpstr .= str_replace( '.jpg', '', $val ) . ',';
					}
				}
	
					$result = $wp_filesystem->put_contents( $xmlfile, trim( $tmpstr, ',' ), FS_CHMOD_FILE);
					if ( $result ) {
						echo 'Success! ' . count( $tmpary ) . ' file-info in list';
					} else {
						echo 'Something Error!';
					}
			} else {
				echo 'directry : ' . $dirname . ' No not exist!';
			}
		} else {
			/* 直接書き込み権限がない場合は、ユーザーに通知を表示する */
			add_action('admin_notice', 'error_notice_function');
		}
	
		die();
	}
	
	add_action( 'wp_ajax_face_list_make', 'face_list_make' );
	add_action( 'wp_ajax_nopriv_face_list_make', 'face_list_make' );
?>
PHP
CopyExpand

アクションフックが二つあるのは、ログインユーザーと非ログインユーザー用で共にフロントエンドにおいてということなので両方とも必要であると思われます。codex の原文は「So, if you want it to fire on the front-end for both visitors and logged-in users, you can do this: 」となってます。
27行目でscandir を使用していますが、これは「Theme Check 」から警告されません。
scandir においては、WP_Filesystem のいくつかあるファイルの中身を探してみましたが見つかりません。調べて見ると、「wp-includes/class-wp-theme.php 」の 「WP_Theme 」クラスにprivate static としてscandir 関数があります。ゆえに、WP_Theme::scandir ですね。説明的には、「Scans a directory for files of a certain extension 」「特定の拡張子のファイルをディレクトリにおいてスキャンします」ということかな?
で、あればあえてこれを使うこともなさそうです。
以上で管理画面内で動かすこの件においては、WP_Filesystem 、およびWordPress においてのAjax を適用させつつ、意図を達成することができました。

・・・

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

Sanbanse Funabashi
2011.01.01 sunrise

Top

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