先日、またまたteratail(テラテイル)を利用しました。質問内容は「現在表示されているページがAMPページかどうかの判別方法」について。
参考https://teratail.com/questions/87735
正直、あまり必要になるケースもないんですが、AMPページにはこのコードを、通常ページにはこのコードを…のようにサンプルコードを紹介するのが難しかったんです。
例えば、WordPressのAMPプラグインを使う場合はis_amp_endpointという関数で条件分岐できるようですが、プラグインを使わずにAMP対応している人もいるので、その関数は使えません。
また、プラグインを使わずにAMPに対応する方法もいくつかあるので、 結局は「そのページがAMPページかどうか」で条件分岐するしかありません。
ただ、これが意外と難しく、良いアイディアは浮かんだものの、それを再現することができずにteratailで質問したというわけです。
AMPページかどうかの条件分岐の関数
こちらが今回完成させたコードです。これをfunctions.php(子テーマでもOK)にコピペすれば、条件分岐に使えます。(解説は後で)
function amp_check_4536() {
$amp_check = false;
$html = get_the_permalink();
$html = file_get_contents($html, NULL, NULL, 0, 100);
$html = htmlspecialchars($html);
$pattern = '/html amp|html ⚡/i';
if(preg_match($pattern,$html,$matches) === 1){
$amp_check = true;
}
return $amp_check;
}
WordPress以外のサイトで使う場合は、get_the_permalink関数の部分を任意の文字列や関数に変更する必要があります。
ちなみに、ローカル環境だと上手くいかなかったので、確かめる時はget_the_permalinkではなく、直に入力してみてください。
活用例
こちらは、「AMPページ用のコード」と「通常ページ用のコード」を条件分岐してショートコード化した例です。
function amp_test() {
if( amp_check_4536() ) {
$adsense_code = '<amp-ad layout="responsive" width=336 height=280 type="adsense" data-ad-client="ca-pub-***" data-ad-slot="***"></amp-ad>'; //AMPページ用のアドセンス
} else {
$adsense_code = '***'; //通常ページ用のアドセンス
}
return '<div class="ad-wrapper clearfix">'.$adsense_code.'</div>';
}
add_shortcode('adsense', 'amp_test');
これで、本文中には[[adsense]]と書くだけで、それぞれのページ用の広告が表示されます。
解説
回答をもらって気づいたんですが、実は、teratailで質問した時のコードが非常に惜しかったんです…!
function amp_check() {
$amp_check = false;
$html = file_get_contents ( 'example.com' );
$html = htmlspecialchars($html);
$pattern = '/<html amp'; //
if(preg_match($pattern,$html,$matches) === 1){
$amp_check = true;
}
return $amp_check;
}
やりたかったことは、ページを読み込んでソースコード化し、<html amp、もしくは、<html ⚡で始まる場合はAMPページ、それ以外なら通常のページ…という条件分岐の関数を定義すること。
このコードでダメだったのは、文字列にする量を制限していなかったこと。
file_get_contents関数はオプションを指定しない場合、ページの情報をすべて文字列にしてしまいます。目に見えるものも、メタ情報のような目に見えないものも全部です。
これの何が問題かというと、例えば、「プラグインなしでAMPに対応する方法」のようなテーマで記事を書いた場合、記事で紹介されているソースコードまで文字列になり、それが正規表現の検索対象になってしまいます。
つまり、「AMPのことを紹介しているだけの通常ページ」がAMPページとして扱われるわけです。
そこで教えていただいたのが、file_get_contents関数で文字列にする量を制限する方法。こちらの回答をベストアンサーにしました。
$html = file_get_contents($html, NULL, NULL, 0, 100);
<html ampも<html ⚡も、ほとんどの場合ソースコードの先頭にあるはずなので、シンプルですごく良い方法だなと思って取り入れましたが、上手くいきました。
上限を100にした理由は、meta情報を検索対象にしたくなかったからです。var_dumpして確認しましたが、それくらいでいいかなと。
懸念点
teratailでも指摘がありましたが、先述の通り、AMPは人によって対応方法が違うので、この条件分岐は万能ではない可能性があります。
ただ、僕が確認したところ、
- AMPプロジェクトの公式サイト
- WordPressのAMPプラグインで生成されたAMPページ
- ネットでよく見かけるAMP対応方法で生成されたAMPページ
など、ほとんどのサイトが同じような構成のHTMLだったので、そこまで心配になる必要もないかと思います。
より精度の高い条件分岐方法
どうしても不安な場合、さらに条件分岐の精度を高める方法もあります。
それは、AMPBench(アンプベンチ)のAPIを使うこと。別の回答者からの情報なんですが、普通に便利なツールでした。
ただ、APIの使い方がいまいちわからずに断念。
- file_get_contents関数で文字列化
- 「”status”: “PASS”」でマッチング
でいけるかなと思ったですが、ダメでした。
また、一旦別のページを経由するからか、動作が重くなるのも使わなかった理由の1つです。
参考としてコード載せておきます。トンチンカンなことしてたらご指摘ください〜
function amp_check_4536() {
$amp_check = false;
$html = 'https://ampbench.appspot.com/api2?url='.get_the_permalink();
$html = file_get_contents($html, NULL, NULL, 0, 100);
$html = htmlspecialchars($html);
$pattern = '/"status": "PASS"';
if(preg_match($pattern,$html,$matches) === 1){
$amp_check = true;
}
return $amp_check;
}
まとめ
相手がどのようにAMPに対応しているかわかる場合は別ですが、ブログなどで不特定多数の人にコードを紹介する場合は、今回の関数はなかなか便利ではないでしょうか?
ぜひ、お試しあれ!(๑•̀ㅂ•́)و✧
(改善点やもう少し上手いやり方があれば教えてくださいっ!)