web-dev-qa-db-ja.com

多数の画像を1ページにロードする "カスタム版"(カスタムテンプレート)

私はグリッド内の多くの注目アイテムをロードするページを持っています。最大56枚の画像をロードしています、そしてそれは少し遅れがあります。これは現在実行中のコードです。

if( count( $postslist ) > 0 ) {
  foreach ($postslist as $post) : setup_postdata($post);
  ?> 
  <div class='oneCell'>
    <?php 
    $image = get_the_post_thumbnail($this_post->ID, 'full size'); 
    $imageSrc = substr($image, strpos($image, "src") + 5);
    $imageSrc = substr($imageSrc, 0, strPos($imageSrc, "\""));
    $finalImage = "<img class='lazy' src='/images/grey.png' data-original='";
    $finalImage .= $imageSrc . "' />";
    $lastImage = "<a href='";
    $lastImage .= catch_that_image();
    $lastImage .= "'>";
    $lastImage .= $finalImage;
    $lastImage .= "</a>";
    echo $lastImage;
    ?>
  </div>
  <?php 
  $currentCount = $currentCount + 1;
  endforeach;
}

私は、コードに問題があることを理解しています。基本的には、ループ内のすべての画像についてデータベースを1回ヒットするため、処理が遅くなります。

誰もがロードをスピードアップするための解決策を手伝ってくれる?私の考えは、データベースからすべてを一度に取得してそこから表示することですが、それをどのように処理するかについてはまだわかっていません。

ありがとうございます。

編集する

申し訳ありませんが、これについてもう少し説明しておく必要があります。

フルサイズのイメージは必要なものなので、get_the_post_thumbnailはフルサイズのイメージを要求しています。投稿の特集画像はその画像で、常に189 x 189になります。

catch_that_image()は、ユーザーがjsライブラリ(magnific-popup.js)を使用して注目の画像(サムネイル)をクリックしたときに表示される、投稿本文の最初の(かつ唯一の)画像を取得するだけです。

編集2:

私の問題はデータベース関連のようです。呼び出しが遅すぎるため、一度に1つずつ呼び出すことはできません(非常に多数あるため)。 1回の呼び出しですべてを取り戻して、そこから処理する方法はありますか?

1
SlackerCoder

答えはeager loadingまたはcache、あるいはその両方です。

熱心なローディング

この擬似コードをご覧ください:

$ids = get_ids_from_a_db_table();
foreach ( $ids as $id ) {
  $row = get_row_from_foreign_table_using( $id );
  echo "Row title for the ID: $id is $row->title";
}

$idsの数がnの場合、この単純なコードはn+1クエリを実行し、最初にIDをロードし、次にIDごとに1つをロードします。

あなたのコードはさらに悪いです、すべてのIDに対して2つのクエリを実行し、1つは添付ファイルの投稿オブジェクトを取得し、もう1つはattachemnt URLを取得します(実際にはWordPressです)

したがって、2n + 1クエリを実行します...

Dbクエリと呼ばれるEager Loadingは、必要なすべてのデータをone dbリクエストのみでクエリすることにより、n + 1(または2n + 1)クエリの問題を解決する方法です(通常は適切なJOIN + WHERE

$data = get_data_from_joined_db_tables();
foreach ( $data as $row ) {
  echo "Row title for the ID: $row->id is $row->title";
}

WordPressでそれをどのように行いますか?次の2つが必要です。

  • 適切な結合とwhere句を追加して、ポストメタテーブルをマージします
  • WP_Queryによって返されるフィールドをフィルタリングして、メタテーブルフィールドを含めます

両方ともクエリフィルタを使用して実行できます。ここでは、それを行うWP_Queryを拡張するクラスです。

class Thumb_Query extends WP_Query {

  protected static $args = array( 'nopaging' => TRUE );

  public function __construct( $args = '' ) {
    if ( empty( $args ) ) $args = self::$args; // defaults
    parent::__construct( $args );
  }

  public function get_posts() {
    add_filter('posts_clauses', array( __CLASS__, 'thumb_filters') );
    $results = parent::get_posts();
    remove_filter('posts_clauses', array( __CLASS__, 'thumb_filters') );
    return $this->parse_images( $results );
  }

  public static function thumb_filters( $pieces ) {
    $meta = $GLOBALS['wpdb']->postmeta;
    $posts = $GLOBALS['wpdb']->posts;
    $pieces['fields'] .= ", thumbs.meta_value as thumb_id";
    $pieces['fields'] .= ", imgs.post_title as thumb_title";
    $pieces['fields'] .= ", imgdata.meta_value as thumb_file";
    $pieces['join'] .= "INNER JOIN {$meta} thumbs ON ({$posts}.ID = thumbs.post_id)";
    $pieces['join'] .= " INNER JOIN {$posts} imgs ON (thumbs.meta_value = imgs.ID)";
    $pieces['join'] .= " INNER JOIN {$meta} imgdata ON (imgs.ID = imgdata.post_id)";
    $where = " AND ( thumbs.meta_key = '_thumbnail_id' AND ";
    $where .= " CAST( thumbs.meta_value AS SIGNED ) > 0 )";
    $where .= " AND ( imgdata.meta_key = '_wp_attached_file' )";
    $pieces['where'] .= $where;
    $pieces['groupby'] = " {$posts}.ID";
    return $pieces;
  }

  protected function parse_images( $rows ) {
    $exts = array('jpg', 'jpeg', 'gif', 'png');
    foreach ( $rows as $i => $row ) {
       $urls = wp_extract_urls( $row->post_content );
       $img = FALSE;
       while ( ! $img && ! empty($urls) ) {
         $url = array_shift($urls);
         $ext = strtolower ( pathinfo( $url, PATHINFO_EXTENSION ) );
         if ( in_array( $ext, $exts ) ) $img = $url;
       }
       $rows[$i]->thumb_link = $img ? $img : '#';
    }
  }
}

このクラスはWP_Queryを拡張するため、親と同じものを受け入れますが、いくつかのフィルターを追加して、Thumnail投稿ID、Thumnail投稿名、およびサムネイルファイルのパスを変更します。

したがって、クエリが50件の投稿を返す場合、101(2n + 1)クエリを実行するサムネイルを表示するために、私のクラスでは1つのクエリのみを実行します。

さらに、結果を出力する前に、クラスはすべての行を解析し、投稿コンテンツから最初の画像URLを抽出し、追加されたフィルターを削除します。

使い方

標準のWP_Query引数を使用します。

$args = array(
  'post_type' => 'portfolio',
  'category_name' => 'featured',
  'posts_per_page' => 50
);

ただし、Thumb_Queryの代わりにWP_Queryを使用します

$portfolio = new Thumb_Query( $args );

次に、ループして出力します。

if ( $portfolio->have_posts() ) {
  $u = wp_upload_dir();
  global $post;
  foreach( $portfolio->posts as $post ) { 
    setup_postdata( $post );
    $f = '<div class="oneCell"><a href="%s" title="%s">';
    $f .= '<img class="lazy" alt="%s" width="189" src="%s" data-original="%s"/>';
    $f .= '</a></div>';
    $title = esc_attr( get_the_title() );
    printf( $f,
      esc_url( $post->thumb_link ),
      $title, $title,
      esc_url( get_template_directory_uri() . '/images/grey.png'  ),
      esc_url( trailingslashit($u['baseurl']) . $post->thumb_file )
    );
  }
  wp_reset_postdata();
}

ループ内では、すべての標準投稿プロパティにアクセスできますが、すべての投稿には追加の4つのプロパティがあります。

  • $post->thumb_idサムネイル添付ID
  • $post->thumb_titleサムネイルの添付ファイルのタイトル
  • $post->thumb_fileアップロードフォルダに関連するサムネイルファイル。'/2014/04/myfile.jpg'など
  • $post->thumb_link投稿コンテンツの最初の画像の完全なURL、または画像が見つからない場合は「#」
3
gmazzap

あなたがしたことを理解するのはかなり難しいです。私の懸念の1つは、あなたがしたのと同じコードの中でget_the_post_thumbnail()catch_that_image()を一緒に使うことです。私はcatch_that_image()関数の知識があり、以前にそれを使用しました。それは抜粋でそれを表示するために最初の画像を検索するためにコーダーによって通常使用されるNice-to-know-functionです。しかし、catch_that_image()なしで同じ結果を得るためのより良い方法があります。特に56個の画像を取得する必要がある場合は、ループとは別に実行される外部関数であるため、サイトの速度は遅くなります。 catch_that_image()は画像を取得するためにすべての投稿に対して実行する必要があるので、56回実行されます。私がここで間違っているなら私を直してください。

ループがどのように見えるかわかりませんが、それは少し面倒なようです。ここに行く最良の方法は、 WP_Queryget_posts と組み合わせて使用​​してループを構築することです。

WP_Queryでは、これを機能させるために1つの引数posts_per_pageを渡すだけで済みます。これを1に設定する必要があります。そうしないと、同じ画像が複数回表示されます。

次に、ループを実行し、post_typepost_mime_typeを使用して投稿に添付されているすべての画像を除外します。 Wordpressはすべての添付ファイルを post type として保存します。すべての添付ファイルがイメージであるとは限らないため、イメージである添付ファイルのみを返すように指定する必要があります。これは post_mime_type で指定されます。

wp_get_attachment_image は、指定されたサイズでこれらの画像を返すために使用されます。あなたのコードでは、これはフルサイズの機能を備えた画像になります。

これはすべて完了していて、完全なループは次のようになります。

<?php 
    $new_query = new WP_Query(array(
        'posts_per_page'   => 1,
    ));

        while ($new_query->have_posts()) : $new_query->the_post();

            $args = array (
                'post_type' => 'attachment',
                'numberposts' => 56,
                'status' => 'publish',
                'post_mime_type' => 'image',
                'parent' => $post->ID
            ); 

            $attachments = get_posts($args);

            if ( $attachments ) {
                foreach ( $attachments as $attachment ) {
                    echo '<div class="oneCell">';
                    echo '<a href="' . get_permalink( $post->ID ) . '">';
                    echo wp_get_attachment_image( $attachment->ID, 'full' );
                    echo '</a>';
                    echo '</div>';
                }
            };

        endwhile;

wp_reset_postdata();

?>   

あなたはちょうどあなたの正確なニーズを満たすために引数を変更する必要があります、しかし、私はこれがあなたが必要とし、そしてこれから働くことができる基本的なプラットフォームであり、これが本当にスピードで非常に役立つことを願っています。楽しい。

編集wp_reset_postdata();を使ってクエリをリセットすることを忘れないでください

1
Pieter Goosen