読者です 読者をやめる 読者になる 読者になる

渡米生活。(日記)

渡米生活。本家から切り離しました。あまり渡米生活に関係のないプログラムネタや音楽ネタなど。

ASUS Z10PE-D8 WS にビデオカードを刺してCUDA8を動かす

ASUS Z10-PE-D8 WS が4枚グラフィックカードを挿せるというので、ただいま奮闘中。

以下、構成です。

1)BIOS設定でメインのVIDEO出力をonboardに変更。

これ、デフォルトでそうなっている、とマニュアルには書いてあるのに、そうなっていなかった…。
カード挿すとQ-Codeが62番を刺して「ピー」とか音がして起動が止まってしまうので、何が悪いのかとマザーボードを箱から出してみたり、奮闘2時間。もしやと思ってBIOSをチェックしたらいつのまにかoffboard deviceになってる…。

BIOSからIntelRCSetup→Miscellaneous Configuration→Active Videoで設定。

2)ドライバとCUDAのインストール

前の記事では.runファイルを使う方法で紹介したのだけれど、ELrepoを使うとrpmで簡単に入るのでそれでやってみる。

nouveauを無効化するところまでは前の記事と同じなので省略。


1) ELrepo をインストール

ELrepoの中のnvidia-detectがドライバを選んでくれるのだけれど、そのためにはまずelrepoをrpmにインポートする必要がある。

$ sudo rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org
$ sudo rpm -Uvh http://www.elrepo.org/elrepo-release-6-6.el6.elrepo.noarch.rpm
$ sudo yum install nvidia-detect

2)cuda RPMをとってくる。

RPMの場合、cudaをインストールしたら勝手にドライバもいれてくれる。
現時点での最新はCUDA8.0なので、nvidiaのホームページに行ってCUDAのrpmをとってくる。

NVIDIAのウェブサイトにある基本コマンドは以下のとおり。

$ sudo rpm -i cuda-repo-rhel6-8-0-local-ga2-8.0.61-1.x86_64.rpm
$ sudo yum clean all
$ sudo yum install cuda

しかし、SL6.Xにこれをやると、以下のエラーが出る。

Requires: libvdpau(x86-32) >= 0.5 

どうしたものかと思ったら、以下のサイトに解決法が書いてありました。ありがたや!

Scientific Linux 6でCUDA: satok weblog

転載すると、

1 /etc/yum.repos.d/linuxtech.repo と言うファイルを作成
[linuxtech]
name=LinuxTECH
baseurl=http://pkgrepo.linuxtech.net/el6/release/
enabled=1
gpgcheck=1
gpgkey=http://pkgrepo.linuxtech.net/el6/release/RPM-GPG-KEY-LinuxTECH.NET

2 以下のコマンドを実行
# yum install libvdpau

とのこと。たしかに、これでyum installが通るようになりました。

3)テスト

CUDA8.0では、テストプログラムのインストール スクリプトが用意されている。
コンパイルしてdeviceQueryを走らせてみる。

$ /usr/local/cuda-8.0/bin/cuda-install-samples-8.0.sh ~ 
$ cd ~/NVIDIA_CUDA-8.0_Samples/
$ make
$ bin/x86_64/linux/release/deviceQuery

すると、一応走るのだけど、GTX 1080だけこんなエラーが。

MapSMtoCores for SM 6.1 is undefined. Default to use 128 Cores/SM

なんか、せっかくのGTX 1080が遅くなっているような感じ?
で、このメッセージで検索をかけてみると、どうやらcuDNN とかいうライブラリが古いらしい

GTX 1080はPascalなので、cuDNNはバージョン5以上を使わなければダメ、とCUDAのdeveloper pageに書いてあるのだそうな。

というわけで、cuDNNのアップグレードの方法を探したら、これまたすでに解決されている方がおられました!

CUDA 8.0とcuDNN 5.1をUbuntu 16.04LTSにインストールする - Qiita

Ubuntsuについてのページですが、cuDNNのインストールの部分はまったく同じです。
これも一応転載しておきます。

https://developer.nvidia.com/rdp/cudnn-download からcuDNN 5.1 for CUDA 8.0をダウンロードする(アクセスするにはメンバー登録が必要)。 ダウンロードしたフォルダで以下のコマンドを実行して、cuDNNのライブラリをCUDAがインストールされているディレクトリにコピーする。シンボリックリンクシンボリックリンクとしてコピーされるように cp には -a をつける必要がある。

terminal
tar xzvf cudnn-8.0-linux-x64-v5.1.tgz 
sudo cp -a cuda/lib64/* /usr/local/cuda-8.0/lib64/
sudo cp -a cuda/include/* /usr/local/cuda-8.0/include/
sudo ldconfig

ちなみに私はcuDNN 6.0 for CUDA 8.0をとってきましたが、問題なく動きました。

ところで、消費電力大丈夫??

実は、いい加減な計算しかしていなかったもので、、電源が4枚挿しに耐え切れるかわからないのでした(汗)

ざっくり計算すると、グラボ1枚につき225W。CPUは1個あたり75W。マザーボードがどれだけ電気食うかわからないけど、まあ1500Wの電源ならギリ大丈夫、、かな?(^^;)

こんなサイトもあるそうです。。

電源容量 ☆ 皮算用 ☆ 計算機。

エックスサーバ間の独自ドメイン引っ越しログ

先日、エックスサーバの落とし穴というタイトルで、エックスサーバ間の独自ドメインホームページの引っ越しが大変だ、という話をしたのですが。

(大変というか、どうしても一時ドメインが繋がらなくなる時間ができてしまう、という仕様になっている)

 

とはいえ、もう新サーバの契約をしてしまったので、独自ドメインが一時不通になるのを覚悟で、エックスサーバ間のワードプレスホームページの引っ越しをやってみました。

結論をいうと、覚悟していたよりはかなりスムーズに移行できました。

以下、その方法です。

 

続きを読む

エックスサーバの落とし穴

ウェブ上ではどこを見てもいいサーバだと高評価が並んでいるエックスサーバですが、、、


本日とんでもない不便が発覚。

 

なんと、エックスサーバ同士の独自ドメインを用いたウェブサイトのサーバ間引っ越しがシームレスにできない!
そんなアホなことがあるか、と思って、サポートに問い合わせたら、方法はない、シームレスに移行したかったら一度外部のホスティングサービスに移って、それからまたエックスサーバに戻ってこいとのお言葉。

 

もちろん、独自ドメインにくっついてるメアドも同様に二段階引っ越しが必要。

やってられるかーーー!!!(怒)

共用サーバなんで、どうしても同居者との相性があります。
実際私が使ってるサーバも、頻繁にwordpressの「更新」ボタンを押すとぐるぐるカーソルが回っちゃってせっかくの変更が全部消える、ということが起きたので、この際別サーバに引っ越ししてみようか、とアカウントを取り直し、引っ越ししようとしたらコレですわ…(脱力)

まあ、そういうことがなくても、複数の独自ドメインを同じサーバで運用していて、やっぱりあとで別サーバに分けたい、とか、いろいろドメインの引っ越しが必要になる場面はあるわけで。

 
昔使っていたcoreserverxreaではもちろん簡単にそれができたので、当然エックスサーバもそうだろうと思っていたら、「できない」とのご返答だったわけです。

どういうことかというと、エックスサーバのドメイン設定は、厳密にエックスサーバの内部のサーバ一つにしか設定できないのです。

本来、各サーバのドメイン設定は重複していても(つまり複数サーバにexample.comドメイン設定があったとしても)、DNSサーバがそのうちのどれかひとつのサーバを指してさえいれば、事実上問題はないはずなんですが。

まあ、長期的には気持ちわるいかもしれんが、1週間やそこらで問題になるとは思えないので、引っ越し時限定で重複設定を許せばいい話なんじゃないか、と思う。

しかし、エックスサーバではそれは許してくれないので、新サーバにドメインを設定したければ、まず旧サーバのドメイン設定を削除しなくてはならない。
で、オソロシイことに、このドメイン設定を削除すると、サポートの言葉を借りるに、

ドメインの設定削除を行いますと、 メールアカウントを含むホームページ構成ファイルなど、 該当ドメインに関する【全て】のデータがサーバー上から 削除されてしまいますのでご注意ください。   

 というわけで、全部ファイル消されちゃうんですよ!!

つまり、旧サーバのファイルやwordpressのデータベースを全部ローカルに保存したとしても、新サーバにアップロードおよび設定が完了するまで、ウェブサイトが見れないのはもちろん、メールすら迷子になってしまうというありさま。
何らかの原因で引っ越しに失敗しても、もはや旧サーバに戻ることもできないのです。

しかも、こうやって旧サーバの設定を削除しない限り、新サーバでドメインの設定ができず、それができないうちは、ホームページ領域にアクセスする方法もなければ、メールの設定もできない。

 

さらに、DNSの変更がいきわたるまで最大24時間と思うと、その間、もしかしたら古いDNSを見たユーザはすでにホームページが消えちゃってる旧サーバを見にいっちゃって、「ファイルが存在しません」とか怪しいページが表示されてしまうわけですよね?
だって、サブドメイン用のディレクトリごと消す、っていってるんだから、「ただいま工事中」の簡単なhtmlファイルすら置けないわけですよ。

こんな怖い仕様のサーバありなの?! と私は思うんだけど、そういうもんなんですか?
ずっとxreacoreserverしかいじってなかったから、サーバー引っ越しなんてシームレスに出来るのが当たり前だと思ってたよ!!!

 

確かにエックスサーバはそこそこ安定してるかもだけど、ワードプレスの更新ボタンでぐるぐるカーソル回っちゃって変更全部消えたとか、コアサーバ時代はなかったし。
不安定になったらいつでもサーバのりかえられたし。
それとも、企業のウェブサイトなんかは、夜中に「メンテナンス中です」とか出して作業するから、シームレスでなくても構わないってことなんでしょうか。

ちょっとコアサーバから引っ越したのは早まったかも…。

3/28追記

結局引っ越ししてみました。思ったよりはスムーズでした。

エックスサーバ間の独自ドメイン引っ越しログ - 渡米生活。(日記)

 

Wordpressで特定のカテゴリ記事のみのイベントカレンダー(イベント名つき)を作成する

Wordpressでイベントカレンダーを表示するプラグインはたくさんあるのですが、多くがカスタム投稿を利用するタイプでして、フリーテーマを使っていたりすると具合が悪いケースがあります。

Wordpressでイベントの告知をするのに、私は通常の投稿記事を使っています。こうすると、綺麗なデザインのフリーテーマとほぼ衝突することなく使えて、イベント情報をスライド表示したりできるからです。
この部分を崩さないまま、イベントカレンダーを作る方法はないか、と探して、結局そこそこ簡単に実装できることがわかりました。
しかも、コードの部分はPHP Code For Posts などのプラグインを入れてそこに書きますので、テーマに手を加える必要がなく、着せ替えも思いのままです。

見た目は以下のスクリーンショットのような形になります。イベント名をクリックするとその記事に飛びます。
上の年月の横にある矢印(>)をクリックすると、翌月のカレンダーを表示します。
(<をクリックすると前月のカレンダーを表示しますが、この実装では本日以前のイベントは見えないようになっていますので、ただのカレンダーが表示されるだけです)

実装はこちらのページで見てください。


ただし、これをやるには、自分である程度のルールを作って記事を投稿する必要があります。

1)カレンダーに表示したい記事のカテゴリを設定し、イベント用の記事の名前の付け方にルールを設ける。

Wordpressの中でイベント告知を投稿記事を使って書く方法は、大きく分けて2つあります。
1つは投稿記事を未来のイベントの日付で作り、No Future Postなどのプラグインで未来の投稿も表示するやり方。これも悪くないのですが、投稿記事の投稿日がイベント日になってしまうため、スライダーでの表示順をいじるのが難しくなる、という問題があります。
多くのスライダーは新しい順に表示してしまうので、1ヶ月先のイベントの記事をスライダーのトップに表示したいのに、1年先のイベントが1番目になってしまう、といったような問題です。

そこで、私は現在、記事のタイトルそのものに日付を入れてしまう、という方法をとっています。これだと、投稿の日付は自由に設定できるので、そこをいじればスライダーの表示順を変えることができます。
ヘボいかな、と思いましたが、やってみると、スライダーでイベント日がタイトルの先頭に見えるのは、お客さんにもわかりやすくて、それほど悪くありません。

しかし、そのためには、記事のタイトルの付け方をあらかじめ決めておく必要があります。
この自前ルールは、あとでコードを書くときに必要になりますので、一度決めたら変えないこと。私はこんな感じにしました。

  1. イベント記事のタイトルは、必ず yyyy/mm/dd(またはyyyy/m/d)で始める
  2. そのあとに半角スペースをあけて、記事のタイトルを書く
  3. 記事タイトル中には半角スペースを含んではいけない。全角スペースはOK
  4. 数日にわたるイベントは、yyyy/mm/dd-dd とする。月をまたぐ場合は、yyyy/mm/dd-mm/dd、年をまたぐ場合はyyyy/mm/dd-yyyy/mm/ddとする。

あ、書いてて気づいた。今のプログラムだと月をまたいで数日にわたるイベントが対応できませんね。あとで直します。。変更しました。

いずれにしても、この方法の良いところは、自前で決めたルールでいくらでもあとで調整が可能なところです。別にタイトルをいじる方法ではなくても、カスタムフィールドの値を使うでもOK。カスタムフィールドに必要な情報を全部分類して入れておけば、あとでプログラムを書くときにかなり楽ができます。

ちなみに、カレンダーに表示するイベント記事用には、EVENTカテゴリ(別にどんな名前でも良い)を割り当てておけば、このカテゴリをスライダーにセットしてトップページにスライド表示できます。私はさらに、カレンダーには表示したいけど、トップスライダーには出したくないイベント用にSCHEDULEカテゴリも作りました。

2)終わったイベントを自動で非公開にするプラグイン(Enable Post Expiration)を入れる。

終わったイベントがいつまでも表示されているのはよくありませんので、私はPost Expiratorというプラグインを使っています。
これは、指定の日時がきたらイベントの公開状態を非公開や下書きなどに自動で変更してくれるプラグインです。「Enable Post Expiration」の項目にチェックを入れなければ適用されませんので、イベント情報記事以外が影響を受けることはありません。

このプラグインを入れたら、カレンダーに表示したい記事全ての「Enable Post Expiration」にチェックを入れ、取り下げる日時を設定します。私は単純に、イベント日当日の23時59分にセットしていますが、イベントが終わってもしばらくはカレンダーに表示しておきたい、という方はもう少し遅らせてもよいかと思います。

Enebale Post Expirationについては、以下のリンクで解説されています。

※ちなみに、このプラグインの使用は必須ではありません。要はWP_Queryでカレンダーに表示する記事を選べれば良いので、単純にあるカテゴリの記事だけ表示して、取り下げるのは自分でやる、という方はそれでも大丈夫です。また、自分でカスタムフィールドなどに別の日付を設定して、それを使うでもOK。

3)PHP Code For Posts など、管理画面からPHPのショートコードを作成できるプラグインを入れる。

カレンダーを作る関数はテーマの中のfunction.phpに書くのが定石ですが、それではテーマの変更が必要になります。テーマがアップデートしたら変更も消えてしまってよくありません。
別にファイルを作り、プラグインとして登録する手もありますが、このカレンダーはかなり使用方法に特化しているので、そこまで一般化して他のサイトで使えるようにする手間が面倒です。

というわけで、管理画面からPHPプログラムを作成しショートコードを作ってくれるプラグインを入れます。別にショートコードを作ってくれるプラグインならなんでもOKです。

PHP Code For Posts については、以下のリンクで解説されています。

4)ショートコードを作成

カレンダーの作成ですが、カレンダーの表示部分についてはほとんど以下のサイトで公開されていたものの丸写しです(使わせていただいてありがとうございます!)

動画で学ぶプログラミング・アプリ開発 Coding with Sara

変更したのは以下の2点のみ。

  1. カレンダーを月曜始まりに変更
  2. カレンダーに紐付ける記事を選ぶ部分

このカレンダーの例題は日曜始まりですが、イベントカレンダーは月曜始まりの方が都合がいいので、以下の1行を加えました。

//曜日を月曜始まりに変更 
$youbi = ($youbi == 0) ? 6 : $youbi - 1;

これは、その前のdate関数で月の1日が日曜なら0、月曜なら1…、土曜なら6の数字が返ってくるので、月曜なら0、火曜なら1、…日曜なら6、に変更するためのものです。こうすると、(この例題プログラムでは)月曜から日曜までのカレンダーを作ってくれます。

5)カレンダーに表示するイベントを選ぶ。

月や年をまたぐイベントに対応し、かつ同日に複数イベントが入った場合にも全部表示するようにしたら、結構面倒になりました…。
具体的には、さきにカレンダーに表示するイベントを選んで一度バッファにFILLしておき、あとでカレンダーに書く、という作業をしています。

このため、指定の範囲内の日付($startdayから$enddayまで)に同じイベントをフィルする関数をつくりました。
$databufは3次元の配列です。

function mycalendar_fillevents($databuf, $startday, $endday, $title, $url) {
	if ($startday > $endday) {
		print 'error, startday > endday <br>';
	}
	$curday = $startday;
	for ($i = 0; $i < $endday - $startday + 1; $i++) {
		$curday = $startday + $i; // カレンダーの日付
		$countid = count($databuf[$curday]); // 同日に複数イベントが入った場合のID
		$databuf[$curday][$countid]["title"] = $title;
		$databuf[$curday][$countid]["url"] = $url;
	}
	return $databuf;
}

さらに、以下の部分でイベントの抽出をしています。
何をやっているかはコメントを見てください。

//
// イベントを抽出するクエリを作成。
// 下の例題は、記事の種類は「投稿」、カテゴリーはeventsかschedule、
// 抽出した結果をソートするのに、Post Expiratorの取り下げ日時を
// 使っている。Post Expiratorが使うカスタムフィールドのキー値が
// _expiration-dateです。これを、meta_value_num、つまり数値として
// 解釈し、ASC(昇順)でソートしろ、ということ。
//
// これは私がPost Expiratorの取り下げ日時をイベント当日
// にしているためで、そうでない場合は別にカスタムフィールドに値を
// 入力してコントロールした方が良いと思います。
// 一番単純な方法は、yyyymmddの書式で_event_dateとか適当なキー値で
// カスタムフィールドに値を入力しておけば、ソートも楽になるかと。
//
//
// extract event list
//
$args = array(
	'post_type'  => 'post',
	'category_name' => 'events,schedule',
	'meta_key'   => '_expiration-date',
	'orderby'    => 'meta_value_num',
	'order'      => 'ASC',
	'posts_per_page' => -1	
	);

// The Query
$the_query = new WP_Query( $args );

// イベント日とそのイベント名、対応する記事へのリンクをおさめる配列を用意。
$databuf = array();

// 選んだ投稿をループしながら、必要な情報を保存。
if ( $the_query->have_posts() ) {
	
	while ( $the_query->have_posts() ) {
		$the_query->the_post();
		$url = get_the_permalink();

		global $post, $id;
		// 非公開記事には頭に「非公開」とついてしまうので、それを削除。テストは非公開記事で行える。
		$articletitle = trim(str_replace('非公開:','', get_the_title()));
		// 半角スペースでタイトルを分割。前半が日付情報、後半がイベントタイトルになる。
		$splits = explode(' ', $articletitle);
		$title = $splits[1];
		
		$datearray = explode('-', $splits[0]);
		
		$startymd = explode('/', $datearray[0]);
		$startyear = $startymd[0];
		$startmonth = $startymd[1];
		$startday = $startymd[2];
		$theday = new DateTime();
		$theday->setDate((int)$startyear, (int)$startmonth, (int)$startday);
		$startym = $theday->format('Ym');
		
		// $startymが現在の表示年月より大きい場合は、残りのイベントも全て同条件で現在のカレンダーの表示範囲外。
		// なので、すぐにloopを出る。
		if ($startym > $page_ym) {
			break;
		}
			
		if (count($datearray) == 1 && $startym == $page_ym) {
			// yyyy/mm/ddのフォーマット。
			// 1日のみのイベントなので、現在のカレンダーの年月に合致した場合のみデータベースにFILLする
			$databuf = mycalendar_fillevents($databuf, $startday, $startday, $title, $url);
			
		} else if (count($datearray) > 1) {
			// 複数日イベント
			// yyyy/mm/dd-dd、yyyy/mm/dd-mm/dd、 yyyy/mm/dd-yyyy/mm/dd のいずれかのフォーマット
			// $datearray[0] = yyyy/mm/dd
			// $datearray[1] は dd, mm/dd, yyyy/mm/dd のいずれか。
			
			$endymd = explode('/', $datearray[1]);
			$endymdcounts = count($endymd);
			
			// try simple case first.
			if ($endymdcounts == 1) {
				// イベント開始日と終了日が同じ月。現在の表示カレンダーの年月のものだけFILLする
				// フォーマットは yyyy/mm/dd-dd.
				if ($page_ym != $startym) {
					// month doesn't match through event period. go to next post.
					continue;
				}
				$endday = $endymd[0];
				$databuf = mycalendar_fillevents($databuf, $startday, $endday, $title, $url);
				
			} else {
				// イベント終了日が開始日と同じ年月にない場合は、イベント期間中のうち表示中のカレンダー年月のみFILLする
				// フォーマットは yyyy/mm/dd-mm/dd または yyyy/mm/dd-yyyy/mm/dd.
				$endyear = $startyear;
				$endmonth = $startmonth;
				$endday = $startday;
				if ($endymdcounts == 2) {
					$endmonth = $endymd[0];
					$endday = $endymd[1];
				} else if ($endymdcounts == 3) {
					$endyear = $endymd[0];
					$endmonth = $endymd[1];
					$endday = $endymd[2];	
				}
								
				$theday->setDate((int)$endyear, (int)$endmonth, (int)$endday);
				$endym =  $theday->format('Ym');
				
				if ($page_ym > $endym) {
					// イベント終了日が現在の表示年月より前の場合は、このイベントをスキップ
					continue;
				} 
				
				$curym = $startym;
				$curyear = $startyear;
				$curmonth = $startmonth;
				// 開始日付は1日かイベント開始日のどちらかになる
				$curday = ($page_ym == $startym) ? $startday : 1;
				
				// 開始年月から終了年月までループ
				while ($curym <= $page_ym) {
					
					if ($page_ym == $curym) {
						// カレンダーの表示中年月と一致したのでFILLする。
						// update start day and end day.
						$startday = $curday;
						$last_day = $day_count;
						// 開始日付は月の最後の日かイベント終了日のどちらか
						$endday = ($curym == $endym) ? $endday : $last_day;
						$databuf = mycalendar_fillevents($databuf, $startday, $endday, $title, $url);
					} 
					
					//次月を取得
					if ($curmonth == 12) {
						//次の月は翌年1月
						$curyear += 1;
						$curmonth = 1;
					} else {
						$curmonth += 1;
					}
					$theday->setDate((int)$curyear, (int)$curmonth, (int)$curday);
					$curym = $theday->format('Ym');
				}
			}
		}
	}
}

//最後にクエリのリセットを忘れずに
wp_reset_postdata();


これら組み合わせたプログラム全体は以下のようになります。

<?php 

date_default_timezone_set('Asia/Tokyo');

//前月と次月を表示する際は、GETで値を受け取る
if (isset($_GET['ym'])) {
	$page_ym = $_GET['ym'];

}else{
	$page_ym = date('Ym');
}


//形式チェック
$timestamp = strtotime($page_ym . "01"); // yyyymmddの書式にする


if ($timestamp === false) {
	$timestamp = time();
}


//今日の日付
$today = date('Ymd',time());
$thismonth = date('n', $timestamp);
$thisyear = date('Y', $timestamp);


//HTML表示用の日付
$html_title = date('Y年 n月',$timestamp);

//前月と次月を取得  mktime(hour, minute, second, month, day, year)
$prev = date('Ym', mktime(0, 0, 0, date('m', $timestamp)-1, 1 , date("Y", $timestamp)));
$next = date('Ym', mktime(0, 0, 0, date('m', $timestamp)+1, 1, date("Y", $timestamp)));

//対象月は何日あるか
$day_count = date('t', $timestamp);

//1日は何曜日か 0:日 1:月 .... 6:土
$youbi = date('w', mktime(0, 0, 0,date('m', $timestamp), 1, date("Y", $timestamp)));

//曜日を月曜始まりに変更 
$youbi = ($youbi == 0) ? 6 : $youbi - 1;

function mycalendar_fillevents($databuf, $startday, $endday, $title, $url) {
	if ($startday > $endday) {
		print 'error, startday > endday <br>';
	}
	$curday = $startday;
	for ($i = 0; $i < $endday - $startday + 1; $i++) {
		$curday = $startday + $i; // カレンダーの日付
		$countid = count($databuf[$curday]); // 同日に複数イベントが入った場合のID
		$databuf[$curday][$countid]["title"] = $title;
		$databuf[$curday][$countid]["url"] = $url;
	}
	return $databuf;
}

//
// extract event list
//
$args = array(
	'post_type'  => 'post',
	'category_name' => 'events,schedule',
	'meta_key'   => '_expiration-date',
	'orderby'    => 'meta_value_num',
	'order'      => 'ASC',
	'posts_per_page' => -1	
	);

// The Query
$the_query = new WP_Query( $args );

// this buffer will be 3dim array
$databuf = array();

// The Loop
if ( $the_query->have_posts() ) {
	
	while ( $the_query->have_posts() ) {
		$the_query->the_post();
		$url = get_the_permalink();

		global $post, $id;
		$articletitle = trim(str_replace('非公開:','', get_the_title()));
		$splits = explode(' ', $articletitle);
		$title = $splits[1];
		
		$datearray = explode('-', $splits[0]);
		
		$startymd = explode('/', $datearray[0]);
		$startyear = $startymd[0];
		$startmonth = $startymd[1];
		$startday = $startymd[2];
		$theday = new DateTime();
		$theday->setDate((int)$startyear, (int)$startmonth, (int)$startday);
		$startym = $theday->format('Ym');
		
		// $startymが現在の表示年月より大きい場合は、残りのイベントも全て同条件で
		// 現在のカレンダーの表示範囲外なのでloopを出る
		if ($startym > $page_ym) {
			break;
		}
			
		if (count($datearray) == 1 && $startym == $page_ym) {
			// 1日のみのイベントなので、現在のカレンダーの年月に合致した場合のみデータベースにFILLする
			// single day event. yyyy/mm/dd
			// year and month matched. fill the event to the buffer.
			$databuf = mycalendar_fillevents($databuf, $startday, $startday, $title, $url);
			
		} else if (count($datearray) > 1) {
			// 複数日イベント
			// multiple days event.
			// date format is yyyy/mm/dd-dd or yyyy/mm/dd-mm/dd or yyyy/mm/dd-yyyy/mm/dd
			// $dataarray[0] = yyyy/mm/dd
			// $dataarray[1] could be dd, mm/dd, yyyy/mm/dd
			
			$endymd = explode('/', $datearray[1]);
			$endymdcounts = count($endymd);
			
			// try simple case first.
			if ($endymdcounts == 1) {
				// イベント開始日と終了日が同じ月。現在の表示カレンダーの年月のものだけFILLする
				// the event will be held within a month.
				// date format is yyyy/mm/dd-dd.
				if ($page_ym != $startym) {
					// month doesn't match through event period. go to next post.
					continue;
				}
				$endday = $endymd[0];
				$databuf = mycalendar_fillevents($databuf, $startday, $endday, $title, $url);
				
			} else {
				// イベント終了日が開始日と同じ年月にない場合は、イベント期間中のうち表示中のカレンダーの年月のみFILLする
				// the event will be held through at least two different months.
				// date format is yyyy/mm/dd-mm/dd or yyyy/mm/dd-yyyy/mm/dd.
				$endyear = $startyear;
				$endmonth = $startmonth;
				$endday = $startday;
				if ($endymdcounts == 2) {
					$endmonth = $endymd[0];
					$endday = $endymd[1];
				} else if ($endymdcounts == 3) {
					$endyear = $endymd[0];
					$endmonth = $endymd[1];
					$endday = $endymd[2];	
				}
								
				$theday->setDate((int)$endyear, (int)$endmonth, (int)$endday);
				$endym =  $theday->format('Ym');
				
				if ($page_ym > $endym) {
					// イベント終了日が現在の表示年月より前の場合はこのイベントをスキップ
					// current calendar is out of bound of this event. go to next post.
					continue;
				} 
				
				$curym = $startym;
				$curyear = $startyear;
				$curmonth = $startmonth;
				// 開始日付は1日かイベント開始日のどちらか
				$curday = ($page_ym == $startym) ? $startday : 1;
				
				// 開始年月から終了年月までループ
				while ($curym <= $page_ym) {
					
					if ($page_ym == $curym) {
						// OK, fill calendar for this month.
						// update start day and end day.
						$startday = $curday;
						$last_day = $day_count;
						// 開始日付は月の最後の日かイベント終了日のどちらか
						$endday = ($curym == $endym) ? $endday : $last_day;
						$databuf = mycalendar_fillevents($databuf, $startday, $endday, $title, $url);
					} 
					
					//次月を取得
					if ($curmonth == 12) {
						//次の月は翌年1月
						$curyear += 1;
						$curmonth = 1;
					} else {
						$curmonth += 1;
					}
					$theday->setDate((int)$curyear, (int)$curmonth, (int)$curday);
					$curym = $theday->format('Ym');
				}
			}
		}
	}
}

/* Restore original Post Data */
wp_reset_postdata();

//カレンダー作成準備
$weeks = array();
$week = '';

//空白を追加
//例) 1日が水曜日だった場合、カレンダーの月曜日から火曜日に空白を入れる
$week .= str_repeat('<td></td>', $youbi);


for ($day=1; $day <= $day_count; $day++, $youbi++){
	if (array_key_exists($day, $databuf)) {
		$week .= '<td>' . $day;
		for ($i = 0; $i < count($databuf[$day]); $i++) { 
			$week .= '<br><a href="' . $databuf[$day][$i]['url'] . '"><small>'.$databuf[$day][$i]['title'].'</small></a>';
		}	
	} else {
		$week .= '<td>'. $day ;
	}
	$week .= '</td>';
	
	//曜日が日曜日、または全ての日付のtdの作成が終わったら
	if($youbi % 7 == 6 OR $day == $day_count){

		//全ての日付のtdの作成が終わったら、残りに空白を追加
		if($day == $day_count){
			$week .= str_repeat('<td></td>', 6 - ($youbi % 7));
		}

		//1週間分のtdをまとめた$weekを$weeks配列に入れる。
		$weeks[] = '<tr>'.$week.'</tr>';
		//新しい週を作成するために$weekを空にする。
		$week = '';
	}

}
?>
	<h4><a href="?ym=<?php echo $prev;?>">&lt;</a>&nbsp;&nbsp;<?php echo $html_title;?>&nbsp;&nbsp;<a href="?ym=<?php echo $next;?>">&gt;</a></h4>
	<br>
	<table id="wp-calendar">
		<thead>
		<tr>
			<th width="14%"></th>
			<th width="14%"></th>
			<th width="14%"></th>
			<th width="14%"></th>
			<th width="14%"></th>
			<th width="14%"></th>
			<th width="14%"></th>
		</tr>
		</thead>
		<tbody>
	 	<?php
		 	//カレンダー表示
		 	foreach ($weeks as $week){
				echo $week;
			}
		?>
		</tbody>
	</table>

カレンダー用のテーブルに、id="wp-calendar"を設定してますが、もちろん別のIDでかまいません。
なぜこうしたかというと、以下のページで紹介されていたカレンダーがカッコよくて、そのままcssを拝借したかったからです。
テーマによっては、自前CSSの追加を許してくれるものがあるので、、、

WordPressでイベントカレンダー wpxtreme


このコードをPHP Code For Postsにセットし、ショートコードを作成します。
あとは、投稿なりページなりでショートコードを入力すれば、その場所にカレンダーが表示されます。

テキストウィジェットでも表示できますが、このカレンダーはイベント名を表示するので、サイドバーなどでは縦に伸びてしまって見づらくなります。
ウィジェットで小さく表示するには、別にショートコードを作成した方がよさそうです。

というわけで、この記事はほとんど人様のコードを拝借して書いたものです。
参考にさせていただいた皆様に感謝!

閲覧期限つきPDFファイルの作成(Adobe Acrobat)

Adobe Acrobatで閲覧期限つきのPDFファイルを作成する方法。
諸処で解説されているけど、自分用メモ。

Appleのプレビューで見ると、期限にかかわらず白くなって見えなくなります。
配布時に、Adobe Acrobatで開くように注意書きが必要かも。

1)Adobe Acrobatで文書を開く。

2)フォームから「編集」を選ぶ。フィールドフォームを検出するかきいてくるので、「いいえ」を選ぶ。(新規作成にするとフォームを自動解析しようとして面倒なことになるので)

3)テキストフィールドを隠したい部分に新規作成、隠す部分を覆うようにして設定。テキストフィールド名はデフォルトのText1でよい(2つ名以降はText2,Text3などとする)。必須フィールドにチェック。

4)テキストフィールドのプロパティを開き,「一般」タブを開き、表示と印刷で「表示」に設定する。

5)「表示方法」タブから,「塗りつぶしの色」で,「白色」を選ぶ

6)全部設定したら、「フォームの編集を綴じる」で編集終了。

7)ページサムネールから、フォームを加えたページを全部選び、右クリックで「ページのプロパティ」を選択。「アクション」を選び、トリガーは「ページを開く」、アクションの選択から「JavaScriptを実行」を選んで「追加」ボタンを押す。

窓が開くので、そこに以下のスクリプトをペースト。

var myDate = "2016/12/31"; //有効期限
var fieldprefix = "Text"; // テキストフィールド名の接頭語
var npages = 29;           // テキストフィールドの数
var message = "閲覧期限を過ぎました。新バージョンの配布につきましてはhttp://www.hoshina-music.com/をご覧下さい。";   //警告メッセージ

var d = new Date();
var s = "yyyy/mm/dd";

if (myDate < util.printd(s, d)) {
  //現在の日付が有効期限を過ぎている場合の処理

  for (i=1; i<=npages; i=i+1) {
      var myField = this.getField(fieldprefix+i);	//テキストフィールド名の取得
      myField.display = display.visible;	//テキストフィールド表示
  }
  app.alert(message);

} else {
  //現在の日付が有効期限内の場合はフィールドを非表示

  for (i=1; i<=npages; i=i+1) {
      var myField = this.getField(fieldprefix+i);
      myField.display = display.hidden;   //テキストフィールド非表示
  }
}


このスクリプトはページを移動するたびに、全ページのフィールド表示をセットしなおすので、無駄といえば無駄なのだけれど、ページが多いといちいちそのページ用のスクリプトをセットするのは手間なのでこうしました。


8)ツールからJavaScriptを選び、「文書のアクションを設定」を選択
「文書を保存する」を選び、以下のJavascriptを設定。
npagesは、作ったテキストフィールドの数。この例では29ページにそれぞれ1フォーム配置して隠したのでこうなりました。

var fieldprefix = "Text"; // テキストフィールド名の接頭語
var npages = 29;           // テキストフィールドの数
for (i=1; i<=npages; i=i+1) {
      var myField = this.getField(fieldprefix+i);
      myField.display = display.visible;   //テキストフィールド表示
}

9)ツールからJavaScriptを選び、「文書のアクションを設定」を選択
「文書を保存した」を選び、以下のJavascriptを設定。

var fieldprefix = "Text"; // テキストフィールド名の接頭語
var npages = 29;           // テキストフィールドの数
for (i=1; i<=npages; i=i+1) {
      var myField = this.getField(fieldprefix+i);
      myField.display = display.hidden;   //テキストフィールド非表示
}

10)文書のプロパティから「セキュリティ」を選び、パスワードのセキュリティをかける。


以上、以下のページを参考にさせていただきました。
http://www.geocities.jp/habacchi1969/down/RIGHT.HTM

Contact form7 + WP-Mail-SMTP + gmailの組み合わせがいつの間にか動かなくなっていた件の対策

WordpressのメールフォームにContact Form 7を使っているのですが、海外で運用しているサーバで問題が発生。

まあ、安いホスティングサーバを使っているので、web サーバにメールサーバが利用可能なのは良いのだけど、メールサーバがスパムのブラックリストに登録されてしまっていて、折角のドメインメールがほとんどの受信者に跳ね返されてしまうのです。
つまり、ドメインメール持っていても、受信専用。送信にはほとんど使えない、という事態に。

というわけで、Contact Form7から送信するアドレスも、それ専用に取得したgmailを使うことになりました。

そのままでは使えないのだけど、wp_mail()関数の振る舞いを変えるプラグインはいくつか出ていて、それを使えば別のサーバからメールを送信させることができます。

とりあえず、うちでは、WP-Mail-SMTPを使っていました。
これに、gmailのログイン情報を登録して、MailerオプションをUse the PHP mail() function to send emailsにしておけば、普通に使えていたのですが……

2014/8/15のgmailSMTPセキュリティポリシーの改訂の影響か、いつのまにかメール送信で失敗するようになっていました。
もう多分何ヶ月もこの状態だったのでは。。

というわけで、以下対処方法。

1)WP-Mail-SMTPのMailerオプションを、Send all WordPress emails via SMTPに変更。
2)From Emailをgmailのアドレスにする。
3)この状態で、一度テストメールを配信。そうすると、テストは失敗するが、gmailから「Google アカウント: ログイン試行をブロックしました」というタイトルのメールが送られてくる。
4)メールを開き、中に書かれているリンク(https://www.google.com/settings/security/lesssecureapps)をクリックし、WP-Mail-SMTPで使うgmailのアカウントでログイン
5)「安全性の低いアプリのアクセス」を「有効」に設定
6)もう一回テストメールを送信して、動作確認

これで、なんとか元通りに動きました。
しかし、gmailが更にセキュリティ制限を強くしてきたら、どうするかな。。コレ。。

※なお、これでセキュリティが多少甘くなるので、パスワードは乱数エンジンで作成するなどして、強固なものに変えておくこと。

子テーマで親テーマのstyle.cssが読み込まれない

久々にWordpressで子テーマを作ったら、style.cssを置くだけでは親テーマのCSSファイルが読み込まれず、文字だけのページになってしまい、暫くハマりました。

以前は、

@charset "utf-8";
/*
 Theme Name:   Academy
 Description:  Twenty Fourteen Child Theme
 Template:     twentyfourteen
 Version:      1.0.0
*/

@import url(“../twentyfourteen/style.css”);

なんてstyle.cssに書くだけで、親テーマとそっくり同じ子テーマ(Academy)の出来上がりだったのですが、最新のWPでは@importは使うな、という仕様になっている模様。

http://codex.wordpress.org/Child_Themes

日本語コーデックスはまだ古い記述なので、ハマった人もいるかも。

正しくは、子テーマ側にfunctions.phpを作り、以下の行を書き込め、ということです。

<?php

add_action( 'wp_enqueue_scripts', 'enqueue_parent_theme_style' );
function enqueue_parent_theme_style() {
    wp_enqueue_style( 'parent-style', get_template_directory_uri().'/style.css' );
}


(他にも関数があればここに書く)

?>

というわけで、親テーマとそっくり同じ子テーマを作るには、最低2つのファイルがいる模様です。
勿論、親テーマのstyle.cssの内容をそっくりそのまま子テーマのstyle.cssにコピーしてしまえば、インポートする必要はないですが。