wordpress WordPress 投稿に挿入した画像を Lightbox のように表示(2)

2014年1月8日

注意

10/12/2014
つい先日気が付いたのですが、この方法を使った場合ページによっては、読み込みが非常に遅くなる場合があることがわかりました。今までは問題がなかったのですが、ある程度投稿の数やアップロードした画像の数が増えるとそうなるのか、WP のバージョンアップに伴いどれかの関数がうまく機能しなくなったのか、原因は今のところ不明です。

よって、この方法は使わないほうが良いと思います。

もし原因がわかれば、追加情報を掲載する予定です。

取りあえずこのサイトでは、「Magnific Popup」という jQuery プラグインを使用することにしました。
関連ページ:「WordPress で Magnific Popup を使ってみる
関連ページ:「WordPress の表示が遅くなったので Debug Bar で調べてみた際のメモ


以前同じタイトルで書いた記事は「他の投稿に対して過去にアップロードした画像を使用(挿入)している場合は対象外」としたが、今回は「過去にアップロードした画像を使用(挿入)している場合」にも対応できるようにする方法のメモ。

PHP の「getimagesize()」と「preg_match_all()」を利用して画像の情報を取得する。

preg_match_all を使って画像の URL を抽出

functions.php に preg_match_all を使って以下のような関数を記述。

投稿に挿入されている画像のリンクには「/wp-content/uploads/」が含まれるので、それを含む a 要素を抽出するパターンを指定して URL を抽出。

追加情報

2014年6月5日

「/wp-content/uploads/」を指定した場合、記事の中にこの文字列を含む記述をするとエラーになるので注意が必要。適宜パターンを環境に合わせたものにする方が良いです。

function getPostImages($mypost){
  if(empty($mypost)){
     return(null);
  }
  if(preg_match_all('/<a &#91;^>]*"(http:[^">]*\/wp-content\/uploads\/[^">]*)"[^>]*>/u',$mypost->post_content,$img_array)){
    $resultArray = $img_array[1];
  }
    return($resultArray);
}

上記の関数を実行すると「投稿に挿入されている画像のリンク」の配列が取得できる(はず)。

getimagesize() を使って画像の幅と高さを取得

以下をテンプレート(single.php など)のループ内の適当な場所に記述。

  • getPostImages($post) で画像へのリンクの配列を取得
  • getimagesize() に渡すパラメータは前後に空白などが含まれているとエラーになる
  • preg_match_all のパターンで空白が含まれないようにしてあるが念のために「trim()」
  • また 以下の形式で getimagesize() に渡すパラメータは「”http://….”」のように「”」が付いているとエラーになったので、preg_match_all のパターンで「”」を除いたものにした
  • 以下の div 要素(id=”post_image_info”)は CSS で非表示にしておく
<div id="post_image_info">
<?php 
$postImages = getPostImages($post);

if($postImages != null) {
  echo "<ol>\n";
  for($i = 0; $i<count($postImages);$i++){
    $img_src = trim($postImages&#91;$i&#93;);
     list($width, $height, $type, $attr) = getimagesize($img_src);
     echo '<li><span class="img_src">'. $img_src .'</span> ';
     echo '<span class="img_width">'. $width .'</span> ';
     echo '<span class="img_height">'.$height .'</span></li>'."\n" ; 
  }
  echo "</ol>\n";
}
?>
</div><!-- end of #post_image_info -->

WordPress の出力(HTML)の例

上記のように記述した場合、出力されるコンテンツ(画像とその情報部分の抜粋)は以下のような感じになる。

<body class="single single-post postid-48....">
  <div id="container">
    <div class="single_content"><!-- リンクが出力される親要素 -->
    ....省略....

    <a  class="mpg" href="http://xxxx/wp-content/uploads/2013/04/enterDomain.gif"><!-- リンク -->
      <img src="http://xxxx/wp-content/uploads/2013/04/enterDomain.gif" alt="" width="300" height="163" class="size-medium wp-image-77" />
    </a>
    ....省略....

    <a  class="mpg" href="http://xxxx/wp-content/uploads/2013/04/pointDomain.gif"><!-- リンク -->
      <img src="http://xxxx/wp-content/uploads/2013/04/pointDomain-300x178.gif" alt="" width="300" height="178" class="size-medium wp-image-78" />
    </a>
    ....省略....

      <div id="post_image_info"><!-- リンクの情報 -->
            <ol>
                <li>
                    <span class="img_src">http://xxxx/wp-content/uploads/2013/04/enterDomain.gif</span> 
                    <span class="img_width">500</span> 
                    <span class="img_height">286</span>
                </li>
                <li>
                    <span class="img_src">http://xxxx/wp-content/uploads/2013/04/pointDomain.gif</span> 
                    <span class="img_width">594</span> 
                    <span class="img_height">353</span>
                </li>
            </ol>
            ....省略....
            </div><!-- end of #post_image_info -->
        </div><!-- end of #single_content -->
    </div><!-- end of #container -->
</body>

CSS

CSS の例

#post_image_info {
  display: none;
}

#bg_layer {
  display: none;
  position: fixed;
  top: 0;
  left: 0;
  height: 100%;
  width: 100%;
  background: #000;
  opacity: 0.70;
  /*filter: alpha ( opacity=65 );*/
  z-index: 1200;
}
#over_layer {
  display: none;
  position: fixed;
  top: 50%;
  left: 50%;
  z-index: 1500;
}
* html #bg_layer {
  position: absolute;
}
* html #over_layer {
  position: absolute;
}
p.title_img {
  font-size: 11px; font-size: 1.1rem;
  color: #FFF;
}
p.close_button {
  display: none;
  position: absolute;
  top: -25px;
  right: -5px;
  cursor: pointer;
  z-index: 2000;
}

jQuery の記述

the_content() により出力される画像のリンクのラップ集合(post_image_links$)を生成。

  • div.single_content の中のリンク(a 要素)を抽出
  • filter() で href 属性に「/wp-content/uploads/」が含まれるものを抽出
var post_image_links$ = $('div.single_content a').filter(function() {
  if($(this).attr('href') && $(this).attr('href').search(/wp-content\/uploads/) != -1) {
    return true;
  }else{
    return false;
  }
});
  • div 要素(id=”post_image_info”)に getPostImages() を使って出力した li 要素(画像の URL, width, height が出力されている)のラップ集合(post_image_info$)を生成
  • 画像のリンクのラップ集合(post_image_links$)の長さが「0」でなく、画像のリンクのラップ集合(post_image_links$)と li 要素のラップ集合(post_image_info$)の長さが等しい場合に以下を実行(長さが違うと何か問題がある)
  • 画像のリンクのラップ集合(post_image_links$)の各要素に「data()」を使ってそれぞれの URL, width, height を設定していく
var post_image_info$ = $('#post_image_info ol li');

if(post_image_links$.length !== 0 && post_image_links$.length === post_image_info$.length){
  post_image_links$.each(function(n) {
    var that$ = $(this);
    var info$ = $(post_image_info$.get(n)); 
    if(that$.attr('href') == info$.find('span.img_src').text()) {
      var width = info$.find('span.img_width').text();
      that$.data('width', width);
      var height = info$.find('span.img_height').text();
      that$.data('height', height);
      var src = info$.find('span.img_src').text();
      that$.data('src', src);
    }
  });
}

Lightbox のように表示するようにする

  • 画像のリンクが存在し、かつ投稿ページの場合は body 要素に背景と閉じるボタンなどを追加するようにする
  • 背景や閉じるボタンをクリックしたら fadeOut で消えるようにする
var img_dir = "http://xxxx/wp-content/themes/テーマ名/images/";

if($('body').hasClass('single') && post_image_links$.length !== 0) {
  var append_elements = '<div id="bg_layer"></div><div id="over_layer">';
  append_elements += '<img class="lightboxlike" src="#" alt="" />';
  append_elements += '<p class="close_button"><img src="' + img_dir + 'close-trans.png" alt="" /></p></div>'
  $('body').append(append_elements);
}

$(document).on('click', '#bg_layer, p.close_button, p.close_overLayer', function() {
  $('#over_layer,#bg_layer ').fadeOut(500);
  return false;
});

Lightbox のように表示する関数を作成


function show_modal_window(img_src, img_width, img_height, my_options) {
//$.extendでパラメータをマージ
var settings = $.extend({
zoom_h: 0.87, //高さの縮小倍率
zoom_w: 0.9, //幅の縮小倍率
extra_h: 30, //高さを比較する際のマージン(ピクセル)
extra_w: 10, //幅を比較する際のマージン(ピクセル)
duration: 700, //アニメーション表示の速さ(ミリ秒)
over_layer: ‘#over_layer’, //画像を表示する領域
background_layer:’#bg_layer’, //背景を表示する領域
img_element: ‘img.lightboxlike’, //表示する画像要素
close_element: ‘p.close_button’ //閉じるボタンの要素
}, my_options || {});

if($(settings.over_layer).css(‘display’) == ‘none’) {
var image_width = img_width;
var image_height = img_height;
$(settings.background_layer).show();
var wh = $(window).height();
var ww = $(window).width();
//画像の高さがウィンドウの高さより大きい場合
if(image_height – (-settings.extra_h) > wh && image_width – (-settings.extra_w) <= ww){ var fixedHeight = wh * settings.zoom_h; var fixedWidth = image_width * (fixedHeight / image_height); $(settings.over_layer).css({ marginTop: '-' + fixedHeight/2 + 'px', marginLeft: '-' + fixedWidth/2 + 'px' }); $(settings.img_element).attr({src: img_src, height:fixedHeight, width:fixedWidth}); //画像の幅がウィンドウの幅より大きい場合 }else if(image_width - (-settings.extra_w) > ww && image_height – (-settings.extra_h) <= wh){ fixedWidth = ww * settings.zoom_w; fixedHeight = image_height * (fixedWidth / image_width); $(settings.over_layer).css({ marginTop: '-' + fixedHeight/2 + 'px', marginLeft: '-' + fixedWidth/2 + 'px' }); $(settings.img_element).attr({src: img_src, height:fixedHeight, width:fixedWidth}); //画像の高さと幅がウィンドウの高さと幅より大きい場合 }else if(image_width - (-settings.extra_w) > ww && image_height – (-settings.extra_h) > wh){
if((image_width – (-settings.extra_w)) – ww > (image_height – (-settings.extra_h)) -wh) {
fixedWidth = ww * settings.zoom_w;
fixedHeight = image_height * (fixedWidth / image_width);
$(settings.over_layer).css({
marginTop: ‘-‘ + fixedHeight/2 + ‘px’,
marginLeft: ‘-‘ + fixedWidth/2 + ‘px’
});
$(settings.img_element).attr({src: img_src, height:fixedHeight, width:fixedWidth});
}else{
fixedHeight = wh * settings.zoom_h;
fixedWidth = image_width * (fixedHeight / image_height);
$(settings.over_layer).css({
marginTop: ‘-‘ + fixedHeight/2 + ‘px’,
marginLeft: ‘-‘ + fixedWidth/2 + ‘px’
});
$(settings.img_element).attr({src: img_src, height:fixedHeight, width:fixedWidth});
}
}else{
$(settings.over_layer).css({
marginTop: ‘-‘ + image_height/2 + ‘px’,
marginLeft: ‘-‘ + image_width/2 + ‘px’
});
$(settings.img_element).attr({src: img_src, height:image_height, width:image_width});
}
$(settings.over_layer + ‘,’ + settings.close_element).fadeIn(settings.duration);
}
}

if($.browser.msie && $.browser.version<7) { window$.scroll(function() { $('#bg_layer').get(0).style.setExpression('top', "$(document).scrollTop()+'px'"); $('#over_layer').get(0).style.setExpression('top',"($(document).scrollTop()+window$.height()/2)+'px'"); }); } [/code] 画像のリンク(post_image_links$)がクリックされたら、上記の関数を使って Lightbox のような感じで表示するようにする。 [code] post_image_links$.click(function() { var that$ = $(this); if(that$.data('width') != undefined && that$.data('height') != undefined) { var width = parseInt(that$.data('width'), 10); var height = parseInt(that$.data('height'), 10); var src = that$.data('src'); show_modal_window( src, width, height) ; return false; } }); [/code]

関連ページ

投稿コンテンツに挿入した画像(メディア)のリンクを抽出する
jQuery で Lightbox のようなモーダルウィンドウを表示
WordPress 投稿に挿入した画像を Lightbox のように表示