«Проблемы» Загрузка МНОГИЕ ИЗОБРАЖЕНИЯ на одной странице (пользовательский шаблон)

У меня есть страница, которая загружает множество элементов в сетке. Загружается до 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; } 

Я понимаю, что есть проблемы с кодом, в основном попадая в базу данных один раз для каждого изображения в цикле, что вызывает медленность.

Может ли кто-нибудь помочь мне с решением ускорить загрузку? Моя мысль захватывает все из базы данных сразу и отображает ее оттуда, но мне еще предстоит выяснить, как с этим справиться.

Благодаря!

Редактировать:

Извините, я должен был объяснить это немного больше:

В get_the_post_thumbnail запрашивается полноразмерное изображение, потому что полноразмерное изображение – то, что ему нужно (189×189). Лучшим изображением в сообщении является то изображение, и всегда будет 189×189.

catch_that_image () просто захватывает первое (и единственное) изображение в теле сообщения, которое будет отображаться, когда пользователь нажимает на изображение (уменьшенное изображение) с помощью библиотеки js (magnific-popup.js).

Изменить 2:

Похоже, моя проблема связана с базой данных. Звонки слишком медленны, чтобы делать по одному (так как их так много). Есть ли способ вернуть все в один звонок, а затем обработать его оттуда?

Ответ – нетерпевая загрузка или кеш или и то, и другое.

Яркая загрузка

Посмотрите на этот псевдокод:

 $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 запросов, первый для загрузки идентификаторов, затем по одному для каждого идентификатора.

У вас еще хуже код, он запускает 2 запроса для каждого идентификатора, один для получения объекта post post, один для получения attachemnt url (это WordPress, а не вы, действительно)

Итак, вы запускаете 2n + 1 запросов …

Желательная загрузка, называемая db-запросом, – это способ решения проблемы с запросами n + 1 (или 2n + 1) путем запроса только одного db запроса всех необходимых вам данных (обычно это делается с использованием надлежащего 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? Вам нужны две вещи:

  • добавьте правильное соединение и где предложения, чтобы объединить таблицу метаданных
  • фильтровать поля, возвращаемые 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 , поэтому принимает те же действия своего родителя, но добавляет некоторые фильтры, чтобы изменить загружаемый идентификатор почтового индекса загрузки, имя столбца заголовка и путь к файлу эскиза.

Поэтому, если ваш запрос возвращает 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 идентификатор прикрепленного $post->thumb_id
  • $post->thumb_title пиктограммы
  • $post->thumb_file файл миниатюр относительно папки uploads, что-то вроде '/2014/04/myfile.jpg'
  • $post->thumb_link полный URL-адрес первого изображения в сообщении или «#», если изображение не найдено

Трудно понять, что вы сделали. Одна из моих проблем – использовать get_the_post_thumbnail() и catch_that_image() вместе в том же коде, что и вы. Я знаю catch_that_image() и использовал ее раньше. Это хорошо знакомая функция, которая обычно используется кодерами для извлечения первого изображения, чтобы отобразить его в выдержке. Как бы то ни было, есть лучшие способы получить тот же результат без catch_that_image() . Я действительно думаю, что это замедляет ваш сайт, поскольку это внешняя функция, которая выполняется отдельно от цикла, особенно если вам нужно получить 56 изображений. catch_that_image() должен запускаться на каждом посту для извлечения изображения, поэтому он выполняется 56 раз. Поправьте меня, если я ошибаюсь.

Я не знаю, как выглядит ваша петля, но похоже, что это беспорядок. Я думаю, что лучший способ пойти здесь – это использовать WP_Query в соединении с get_posts для создания вашего цикла.

В WP_Query вам нужно будет передать только один аргумент, чтобы выполнить эту работу, posts_per_page . Вам нужно будет установить это значение 1 , иначе вы получите одно и то же изображение несколько раз.

Далее следует запустить цикл и отфильтровать все изображения, прикрепленные к сообщению, используя post_type и post_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();