静的サイトをWordPress化

今更感はあるのですが、管理サイトの一部をWordPress化しました。


タイトルは一応静的サイトとなってますが、厳密には静的サイトではありません。PHPSmartyを使って動的に処理して、WordPressでも分離されているようにヘッダーとかフッターなどは分けたりしてました。ただデータベースはなくて、大規模なシステムではなく、一応動的サイトではあるものの静的サイト寄りでした。今後サイト内部でページを増やそうと思ったのですが、そうなると自作の簡易システムでは難しいため、重い腰を上げてWordPressを導入してみました。


WordPressの知識が全くない0からのスタートだったので、固定ページという概念があることも知らなかったのですが、これがあるならさっさと導入すれば良かったと思ったりしました。ブログじゃないっぽいサイトでもソースを見るとWordPressで生成されてたりするので、一応そういったことも出来るんだろうとは思いつつも、どうしてもWordPressはブログのためのシステムというイメージがあったのです。


下位ディレクトリにWordPressをインストールしてこれまでのシステムと併用ということも手っ取り早いので考えましたが、この際一新しようと思いました。結果、そのようにして良かったと思います。結果的にWordPressの関数を多用して依存してるところがあり、これまでのシステムの部分でこれが使えないと辛いな、と思ったので。


WordPress化にあたって色々躓きましたが、その一部をメモ書きしておきたいと思います。

ショートコードでのテンプレート読み込み


静的サイトでは記事内でバナーなど定型的なサブコンテンツを挟んでました。WordPressにはget_template_partというテンプレートを読み込む関数があるので、それをショートコード経由で実行しようと思いました。記事内、つまり投稿画面なのでショートコードで実行する必要があります。


ところがそのようなショートコードを書いても、指定位置に来なくて記事内のトップに来ます。多分、記事内で順に処理をしていくのではなく、the_contentが実行されてから最初に全てのショートコードの処理を行い、その際にget_template_partが実行されているのではと思いました。ただWordPressの内部を見てないので、違っているかもしれません。


なので、元の簡易システムの時と同様、サブコンテンツのHTMLをヒアドキュメントの変数に格納することにしました。変数なら問題なく、指定位置に書き出されます。[insert_template template="sub_contents_A"]とかみたいにしてテンプレートを判別する文字列を渡して、functions.phpの方で条件分岐してHTMLを返します。

srcなどでショートコードが効かない


直感的にセキュリティで効かないようになっているのかなと思いましたが、やはりそのようです。add_filterでwp_kses_allowed_htmlという関数をフックして設定すると除外設定が出来るようです。以下のような感じです。

<?php
add_filter('wp_kses_allowed_html', 'my_wp_kses_allowed_html', 10, 2);
function my_wp_kses_allowed_html( $tags, $context ) {
	$tags['img']['src'] = true;
	return $tags;
}
?>


ただ自分の場合、上記でもうまく動作しない場合がありました。記事内で元々Smartyのif文でPCとモバイルで画像を分けている部分があったのですが、ショートコードではif文が使えません。そのため以下のサイトのコードを使用しました。


http://unguis.cre8or.jp/web/3518


それでsrc内でモバイルだったらそれ用の画像が読み込まれるようにファイル名の文字列を足す処理を書いてましたが、これがどうも弾かれてしまうようです。


だけど発想の転換というか、src内でif文が使えたらスマートだけど、ifは外に出してPCとモバイル用のimgタグ2つ書いて条件分岐すれば弾かれないんじゃないか、と思い浮かびました。やってみると、正解で無事動作しました。

挟む系のショートコードを使うとpタグのペアが崩れる


今のデザインではhタグの中にタグはありませんが、今後デザインの変更でspanタグなどを入れたい場合を考えて、ショートコードで書き出すようにしようと思いました。こうしておけば、デザイン変更などでspanタグが増えても、投稿画面での入力は[h3][/h3]などの記述のままで良く、楽です。そして一括で変更出来ます。直書きだと過去記事を置換処理しなければいけません。


編集しててある時ソース見て気付いたのですが、pタグがどうも閉じ忘れ状態になっているのです。pタグはWordPressの自動生成です。原因特定に悩みましたが、閉じ忘れの場所はhタグの付近であることから、ショートコードが原因かもしれないと思いました。


やはりショートコードが原因で、以下のサイトのコードで解決しました。


https://elearn.jp/wpman/column/c20141022_01.html


pタグが自動生成されるのはWordPressのwpautop関数によるものですが、これが実行される前に上記のようなショートコードを実行してしまおうというものです。wpautopが実行されてからショートコードが実行される場合、wpautopは[h3][/h3]をタグではなく単なる文字列として解釈する訳ですので、内部で辻褄が合わなくなるのも想像出来ます。


もしかしたら前記のテンプレートの読み込みも、この処理順操作の方法で何とかなりそうな気もするけど、どうなんでしょうか。

wpcf7mailsentが効かない


これまでSmartyに対応したあるメールシステムを利用させて貰っていましたが、WordPress用に切り替える必要がありました。そこでWordPressでは王道のContact Form 7を使うことにしました。


しかしどうも自分の環境ではイベントのwpcf7mailsentが発火せず困ってました。wpcf7mailsentにより完了ページへ遷移させたかったのです。すごく悩みましたが、以下のサイトのlengthで要素の有無により判定しページ遷移させる方法で解決しました。


https://stackoverflow.com/questions/17921032/contact-form-7-redirect-with-on-sent-ok-doesnt-work


これも発想の転換というか、やってることは当たり前で大したことではないんだけど、こういった回避策が思い浮かぶのは大事だなと思いました。

index.phpやsingle.phpで記事が取得できない


一通り固定ページの編集が終わって、index.phpやsingle.phpを編集しようと思った時、記事が取得できない症状に悩みました。コード的には問題ないと思われるのに、何故と悩んでましたが、WordPressの設定が原因でした。


自分みたいに固定ページ(静的サイト)があって、その一部にブログシステムがある構成にしたい場合、フロントページを設定する画面の「投稿ページ」という項目で、任意の固定ページを設定する必要があるのでした。この固定ページはダミーのようなもので、タイトルとスラッグ名だけ設定する感じになります。固定ページ一覧にはあるものの、このスラッグ名のページ(例えばhoge.com/blog)でis_page関数の戻り値を見てみると、falseになります。つまり固定ページとしては扱われていません。


また、パーマリンク設定のカスタム構造で/blog/%category%/%postname%/などにします。

投稿ページトップのスラッグ名が取得できない


よくよく考えれば以下の関数では取得できなくて当然なのですが、index.phpを編集し始めた時にスラッグ名が取得出来ないことに躓きました。主に固定ページで、スラッグ名を取得してそれを元に何らかの処理をするよう記述していました。

<?php
function get_slug_name() {
	$page = get_post(get_the_ID());
	return $page->post_name;
}
?>


この記述の場合、トップや検索ページ等だと最初に表示されてる記事のスラッグ名が返ることになります。トップは記事単体ではないのでこれではスラッグ名が取得できないのは当たり前なんですが、編集中この関数でスラッグ名を取得していることを忘れてて嵌まりました。結局、投稿ページのトップは、スラッグ名による判別ではなくis_homeを使うことで解決しました。


また、念の為上記の関数を以下のようにして単体の記事以外だったら空の文字列が返るようコードを変えました。この関数にis_homeの場合を書いてダミーの固定ページのスラッグ名が返るような処理を追加しても良いかもしれません。

<?php
function get_slug_name() {
	if (is_single() || is_page()) {
		$page = get_post(get_the_ID());
		return $page->post_name;
	}
	return '';
}
?>

Yoast SEOのメタの画像URLにショートコードが入る


SEO用のプラグインとしてYoast SEOを使うことにしました。


そこで困ったのが、メタの画像URLにショートコードが入ってしまう点です。記事内の画像URLは絶対的な直書きではなく、特定のディレクトリを返すショートコードを書いてどの環境(ローカル・テスト・本番)でも問題なく表示出来るようにしています。


投稿記事を参照したい場合、$post->post_contentの場合ショートコード実行前の生の状態で返ってしまうので、以下の記述が望ましいとされています。

<?php
apply_filters('the_content', $post->post_content);
?>


ですが、Yoast SEOは生のデータの方を参照しているようです。


以下のような感じでフックを使うことで解決しました。

<?php
function wpseo_fix_twitter_image($img) {
	if (strpos($img, '[get_template_directory_uri]') !== false) {
		return str_replace('[get_template_directory_uri]', get_template_directory_uri(), $img);
	}
	return $img;
}
add_filter( 'wpseo_twitter_image', 'wpseo_fix_twitter_image');
?>

reCaptcha等が読み込まれない問題


今回WordPress化の序にSSL化もやっておこうと思いました。去年くらいから無料でLet's EncryptというSSLが使えるようになりましたが、それが最近もっとお手軽に使えるようになったのです。


URLがhttpsになってからiOS Simulatorでサイトを見ると、外部サーバーから読み込まれるjsなどがSSL証明書が信用出来ないと全部弾かれてしまっている状態になりました。ちなみに自サイトだけでなくYahoo!とかも同じようでした。以前はiOS Simulatorでこんなこと起きなかったんだけどなぁ…。。


全てではないのですが、実機のiPad miniAndroidで確認しても弾かれるものがあったので、上記からSSL化したことが原因かと勘違いしました。これが原因かと思い、丸一日調べましたが全く情報がなく、解決せず。しかし結局原因は恐らく広告ブロックでした。調べても情報がないのは当然です。


ただ広告ブロックを解除すると読み込めるものの、再度広告ブロックをしても読み込めるので何とも言い難いところもあるのですが、再度広告ブロックしても読み込めるのはキャッシュかもしれませんね。読み込めなかった時に広告ブロックを解除すると確実に読み込めるので、これが原因と考えるのが無難でしょうか。


何にせよreCaptchaで認証して貰わないと次のステップへ進めないので、DOM解析してreCaptchaが読み込まれてなかったら警告表示するようにしました。広告ブロックが原因であろうことを伝えることが出来れば、ユーザー側も何故先に進めないのかと悩むことがなくなり良いかと思います。


iOS SimulatorでSSL証明書のエラーが出る原因は未だに分かりません。


追記


SSL証明書のエラーが出るのは、以前通信を見るためにインストールしたCharlesの設定が原因でした。

https・www無し→https・www有りのリダイレクトがうまくいかない


ネットに色んな正規化の記述がありますが、どれを試してもhttps・www無しからhttps・www有りへのリダイレクトがうまくいかなくて悩みました。


しかし原因は前項と同じような単純なことで、www無しのドメインSSLの申請をしてなかったのが原因です。www無しではhttpsは存在しないのだから、当然のことです。使っているのはwww有りなので、そちらだけ申請すれば良いかと直感的に思ってしまったことと、ロリポップの表記がwww無しが一番上にあり、これはサブドメインを含めて全てにまとめてチェックをするようなものかと勘違いしてしまったためです。


文字では分かりづらいですが、以下のような感じになってます。



リダイレクトがうまくいかない時、404がWordPressの404ではなくロリポップ側のものが表示されてたため、.htaccessの設定云々ではなく根本的に何か間違ってるかも、と思ったのが解決のきっかけでした。

アクセスしてくるボットの変化


ここからは躓いたことではありませんが、WordPress化して気付いたことです。


アクセスしてくるボットに変化がありました。例えばREQUEST_URIの値が「/ads.txt」となっているアクセスがあったり。これまでこのようなアクセスはなかったし、今もトップにads.txtなんて設置してないんですけどね。


結構このアクセスがあるので、ads.txtとは何なのかと調べると、簡単に言えばなりすましサイトに広告料が渡らないよう正規のサイトに予め設置しておくテキストファイルのようです。今年の5月に発表された規格のようで、かなり最近の話ですね。WordPressにして何故突然このようなアクセスが増えてきたのかは不明です。


以前にもちらっと書いた、国内のISPやモバイル回線を使ったボットであろうアクセスにも変化がありました。アクセスがあってすぐに以下のようなUAで「/apple-touch-icon-120x120-precomposed.png」「/apple-touch-icon-120x120.png」にアクセスするようになりました。

MobileSafari/604.1 CFNetwork/887 Darwin/17.0.0
MobileSafari/602.1 CFNetwork/811.4.18 Darwin/16.5.0


スマホ用のアイコンは設置してますが、多数あってごちゃごちゃしてるので特定の画像フォルダにまとめています。当然そのフォルダに読みに行くようメタを記述しています。ですが、ads.txtと同様トップにアクセスしてくるようです。


それと、同じく上記のモバイル回線ですが、以下のようなUAでのアクセスもありました。

Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) AppleWebKit/601.2.4 (KHTML, like Gecko) Version/9.0.1 Safari/601.2.4 facebookexternalhit/1.1 Facebot Twitterbot/1.0


auの回線ですが、明らかに一般ユーザーではないと思います。一般ユーザーがUAにわざわざFaceboookやTwitterのボットを表すUAを組み込まないですよね。この1秒前にiPhoneUAでアクセス、この1秒後に上記のアイコンへアクセス、といった動作です。やはりこれらはボットなのであろうと思いました。しかし目的は未だによく分かりません。