PHP
WordPress
レスポンシブ
AMP
amp-img

WordPressテーマ内で巧くレスポンシブイメージに対応できるコードを自作した話

我が2017-by-wkwkrnhtをAMP対応するうえで、雑にsrc属性とsrcset属性内にURLだけ出力していたところ、元画像より指定解像度が高い場合に、オリジナルを重複して出力してしまう仕様でした。これは、通常ページでも同様です。そこで、元画像の解像度より低解像度のものをsrc属性内に出力し、余分なものを出力しないことを目標に関数を自作してみましたので、ご査収ください。なお、断りがない限り、

コード紹介

以下のget_yes_imageget_no_imageは自作関数なので、適宜読み替えて頂ければ幸いです。また、うちのテーマ内での画像サイズの名前には接尾辞として、fullcrop(1:1の意味)が必ず付いているので、それを基に判定している部分があります。

定義されている画像サイズを調べる関数

function get_wkwkrnht_img_sizes($suffix){
    global $_wp_additional_image_sizes;
    $origin_sizes = get_intermediate_image_sizes();
    $sizes        = array();
    for($i = 0;$i < 4;++$i){
        array_shift($origin_sizes);
    }
    foreach($origin_sizes as $s){
        $sizes[$s] = array(0,0);
        if(isset($_wp_additional_image_sizes)===true&&isset($_wp_additional_image_sizes[$s])===true){
            $sizes[$s] = array($_wp_additional_image_sizes[$s]['width'],$_wp_additional_image_sizes[$s]['height']);
        }
    }
    if($suffix==='crop'){
        for($j =0 ;$j < 13;++$j){
            array_shift($sizes);
        }
        return $sizes;
    }elseif($suffix==='full'){
        for($k = 0;$k < 13;++$k){
            array_pop($sizes);
        }
        return $sizes;
    }else{
        return $sizes;
    }
}

冒頭のforeachまでのところで、グローバル変数から画像サイズを全て取得し、ユーザーで設定可能なものを除外しています。これらを許可した場合に、サイズの昇順ないしは降順というルールが崩れてしまうので、そうしました。こちらの記事がベースなので、それらも含める場合は、元ネタの該当部分を復活させる必要があります。以降は、サフィックスが指定のもの立っている場合は、それに該当するものだけ、そうでない場合は全部を値として返すという処理をしています。

src属性とsrcset属性を出力する関数

function get_wkwkrnht_img_srcs($suffix){
    $sizes  = get_wkwkrnht_img_sizes($suffix);
    $srcs   = array();
    $srcset = '';
    $i      = 0;
    if(has_post_thumbnail()===true){
        $over_time  = 0;
        $img_max    = wp_get_attachment_image_src(get_post_thumbnail_id(),'full');
        $origin_src = $img_max[0];
        $img_max    = array('width'=>$img_max[1],'height'=>$img_max[2]);
        foreach($sizes as $size){
            if($size['width'] > $img_max['width']){
                ++$over_time;
            }elseif($size['height'] > $img_max['height']){
                ++$over_time;
            }
        }
        for($k = 0;$k < $over_time;++$k){
            array_shift($sizes);
        }
        $sizes_key  = array_keys($sizes);
        foreach($sizes_key as $size){
            $srcs[] = get_yes_image($size);
        }
    }else{
        $origin_src = get_no_image('wkwkrnht-thumb-160-' . $suffix);
        $sizes_key  = array_keys($sizes);
        foreach($sizes_key as $size_key){
            $srcs[] = get_no_image($size_key);
        }
    }
    foreach($sizes as $size){
        if($i > 0){
            $srcset .= ',';
        }
        $srcset_temp = $srcs[$i]. chr(0x20) . $size[0] . 'w';
        $srcset     .= $srcset_temp;
        ++$i;
    }
    return 'src="' . $origin_src . '" srcset="' . $srcset . '"';
}

このテーマ自体がブログ向けなので、簡素にサムネイルを持っているかどうかだけで、条件分岐しています。そこから先は、該当する画像のURLを取得して配列にし、その配列をsrcset属性へと合成、また、別口でオリジナルを保持してsrc属性に代入して、それらを合成した文字列を返すという流れになっています。

そして、今回の肝となる処理がサムネイルを持っているページのみ行うものです。それ自体のIDを基にwp_get_attachment_image_srcの返り値と定義済みの合図とを比較して、幅と高さいずれかが大きいものを全て、画像サイズの配列から消してから、URL取得の流れになっています。このテーマの場合は、配列の並びが取得時点で降順となっているため、先頭から何個という処理になっていますが、そうでない場合は上記の画像サイズを取得する時点で、幅か高さで並べ替えをしておく必要があります。

まとめ

自分がさっと見た範囲では、このような記事がなかったので書いてみました。本体はレスポンシブイメージに対応したけれども、AMP対応で、となるとこういう風に自分で出力してしまうのが早い気もします。もし、このような関数が内蔵されていたら、そちらを使うのを強くお勧めしますし、教えてください。また、ループ処理が多いので、キャッシュを使った方がいいのかもしれません。その場合は、URLを出力する方の関数に引数を追加して、トランジットのIDをつくるなどといった処理を追加する必要がありそうです。以上、名無しの新人より。