Один запрос для выбора случайных изображений из X уникальных родителей? - PullRequest
0 голосов
/ 30 июня 2010

Я использовал этот запрос, чтобы случайным образом выбрать всего $limit -изображений (вложений), каждое из которых было уникальным и случайно выбранным родителем.

$query="SELECT {$wpdb->posts}.post_parent, {$wpdb->posts}.ID
                    FROM {$wpdb->posts}                    
                    INNER JOIN {$wpdb->term_relationships} ON ({$wpdb->posts}.post_parent = {$wpdb->term_relationships}.object_id)
                    INNER JOIN {$wpdb->term_taxonomy} ON ({$wpdb->term_relationships}.term_taxonomy_id = {$wpdb->term_taxonomy}.term_taxonomy_id)
                    WHERE {$wpdb->posts}.post_type = 'attachment'
                    AND {$wpdb->term_taxonomy}.taxonomy = 'category' AND {$wpdb->term_taxonomy}.term_id IN ('{$wpdb->escape($category_filter)}')
                    AND {$wpdb->posts}.post_password = ''
                    AND {$wpdb->posts}.post_mime_type IN ('image/jpeg', 'image/gif', 'image/png')                                                  
                    GROUP BY {$wpdb->posts}.post_parent
                    ORDER BY {$order_by}                                   
                    LIMIT {$limit};";

( полный код на pastebin )

К сожалению, у него есть три ошибки:

  1. Я думаю, что пароль-проверка неверна, так как она проверяет вложение, а не parent_post, верно?(поддерживает ли WordPress вложения галереи, защищенные паролем?)случайные посты, но внутри всегда одни и те же картинки (первая).

Итак - я скромно прошу вашего SQL-фу.Как один оба выбирают случайного родителя (сначала проверяя опубликованный статус), а затем случайный идентификатор изображения, принадлежащий этому родителю, все в одном запросе?

(я мог бы выбрать все вложений, упорядоченные в случайном порядке, перебирая их все и просто получая первые $limit от уникальных родителей. Но это приводит к тому, что родители с большим количеством изображений выбираются слишком часто.)


«Когда ответ ускользает от вас, измените вопрос ...»

Я только что выпустил плагин , который позволяет массово выбирать «избранные изображения поста», прямо измедиа библиотека.Ядро моей функции составило от ~ 45 строк до этого;

foreach($potential_parents as $parent){
   if(has_post_thumbnail($parent->ID)) {
      $image = get_post_thumbnail_id($parent->ID);
   }
}

Это не случайно, но сайт выглядит лучше, и посетителям легче перемещаться по контенту теперь, когда миниатюры соответствуют друг другу.

Ответы [ 3 ]

0 голосов
/ 03 июля 2010

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

$potential_parents = $wpdb->get_results(
        "SELECT DISTINCT {$wpdb->posts}.ID, {$wpdb->posts}.post_title 
        FROM {$wpdb->posts} 
            LEFT JOIN $wpdb->postmeta wpostmeta ON ({$wpdb->posts}.ID = wpostmeta.post_id) 
            LEFT JOIN $wpdb->term_relationships ON ({$wpdb->posts}.ID = $wpdb->term_relationships.object_id) 
            LEFT JOIN $wpdb->term_taxonomy ON ($wpdb->term_relationships.term_taxonomy_id = $wpdb->term_taxonomy.term_taxonomy_id) 
        WHERE $wpdb->term_taxonomy.taxonomy = 'category' AND $wpdb->term_taxonomy.term_id IN({$wpdb->escape($category_filter)}) 
        AND {$wpdb->posts}.post_type = 'post' 
        AND {$wpdb->posts}.post_status LIKE 'publish' 
        AND {$wpdb->posts}.post_password = ''           
        ORDER BY {$order_by};");
$imglists = array();
$parent_titles = array();
$count = $limit;
foreach($potential_parents as $parent){
    $images = $wpdb->get_results(
        "SELECT {$wpdb->posts}.ID  
        FROM {$wpdb->posts} 
        WHERE {$wpdb->posts}.post_parent = {$parent->ID}
        AND {$wpdb->posts}.post_type = 'attachment' 
        AND {$wpdb->posts}.post_mime_type IN ('image/jpeg', 'image/gif', 'image/png') 
        ORDER BY {$order_by} 
        LIMIT 1;"); 
    if($images){
        $imglists[$parent->ID] = $images;
        $parent_titles[$parent->ID] = $parent->post_title;
        if(--$count < 1){break;}
    }       
}   
foreach($imglists as $parent_id => $imagelist){
    $imgurl = wp_get_attachment_image_src($imagelist[0]->ID, $size); 
    if($imgurl === false){continue;} //the image doesn't exist? 
    $img_width = $imgurl[1];
    $img_height = $imgurl[2];
    $imgurl = $imgurl[0];       
    $selection[] = array('post_url'=>get_permalink( $parent_id ), 'post_title' => wp_specialchars($parent_titles[$parent_id]),'post_id'=>$parent_id, 'img_src'=>$imgurl, 'width'=>$img_width, 'height'=>$img_height);                   
}
return $selection;

Итак, в основном, сначала получите один большой результат со всеми опубликованными постами в категориях. Затем несколько небольших запросов, извлекающих один идентификатор вложения в каждом цикле, пока $limit не будет заполнено.

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

Тем не менее, все еще ищем это эффективное решение для одного запроса. :)

0 голосов
/ 31 декабря 2011

Я решил это!Повторно обнаруженные подзапросы и ключевое слово IN сегодня.:) Кажется, достаточно быстро и правильно загрузить.

$images = $wpdb->get_results(
    "SELECT SQL_SMALL_RESULT DISTINCT wp_posts.post_parent, wp_posts.ID 
    FROM wp_posts 
    WHERE wp_posts.post_parent IN (
        SELECT SQL_SMALL_RESULT DISTINCT wp_posts.ID
        FROM wp_posts       
            LEFT JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id) 
            LEFT JOIN wp_term_taxonomy ON (wp_term_relationships.term_taxonomy_id = wp_term_taxonomy.term_taxonomy_id) 
        WHERE 
            wp_term_taxonomy.taxonomy = 'category' 
        AND wp_term_taxonomy.term_id IN({$wpdb->escape($category_filter)}) 
        AND wp_posts.post_type = 'post' 
        AND wp_posts.post_status = 'publish' 
        AND wp_posts.post_password = ''             
        ORDER BY {$order_by}
    )       
    AND wp_posts.post_type = 'attachment' 
    AND wp_posts.post_mime_type IN ('image/jpeg', 'image/gif', 'image/png') 
    ORDER BY {$order_by} 
    LIMIT {$limit};"
);
$selection = array();                           
foreach($images as $img){
    $imgurl = wp_get_attachment_image_src($img->ID, $size); 
    if($imgurl === false){continue;} //the image doesn't exist? 
    $img_width = $imgurl[1];
    $img_height = $imgurl[2];
    $imgurl = $imgurl[0];       
    $selection[] = array(
        'post_url' => get_permalink($img->post_parent), 
        'post_title' => wp_specialchars(get_the_title($img->post_parent)),
        'post_id' => $img->post_parent, 
        'img_id' => $img->ID, 
        'img_src' => $imgurl, 
        'width' => $img_width, 
        'height' => $img_height
    );                      
}
return $selection;
0 голосов
/ 03 июля 2010

Хорошо. Вот один из способов сделать это, используя WordPress API. Это очень неуклюже и очень медленно, но кажется правильным. Конечно, я бы предпочел, чтобы MySQL сделал всю эту работу.

$count = $limit;
$parent_posts = get_posts(array(
    'post_type' => 'post',
    'numberposts' => $limit,
    'post_status' => 'publish',
    'category' => $category_filter,
    'orderby' => $order_by
)); 
foreach ($parent_posts as $parent_post) {
    $attachments = get_posts(array(
        'post_parent' => $parent_post->ID,
        'post_mime_type' => '"image/jpeg", "image/gif", "image/png"', //Not sure if this is functional http://wordpress.org/support/topic/361633
        'post_type' => 'attachment',
        'numberposts' => 1,
        'post_status' => 'inherit',
        'orderby' => 'rand'
    ));
    foreach($attachments as $attachment){ //NOTE: $attachments might be empty
        $imgurl = wp_get_attachment_image_src($attachment->ID, $size); 
        if($imgurl === false){continue;} //bail, don't add to selection, don't decrease $count  
        /*[... do whatever with the image, add it to $selection ...]*/  
        if(--$count < 1){return $selection;}
    }
}

Обратите внимание, что вы должны обернуть это в цикл while, чтобы убедиться, что $selection заполнено. У какого-то потенциального $parent_posts может не быть детей.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...