单个查询从X个唯一父母中选择随机图像?

时间:2010-06-30 18:19:00

标签: mysql wordpress

我已经使用此查询随机选择了总共$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};";

full code at pastebin

不幸的是它有三个错误:

  1. 我认为密码检查不正确,因为它测试附件而不是parent_post,对吧? (WordPress甚至支持受密码保护的图库附件吗?)

  2. 它肯定不会检查post_status = "publish"

  3. 的父级
  4. 它正确选择随机帖子,但总是在其中相同的图片(第一个)。

  5. 所以 - 我谦卑地问你的SQL-fu。一个两者如何选择随机父级(首先检查已发布状态),然后选择该父级拥有的随机图像ID,所有这些都在一个查询中?

    (我可以选择所有附件,随机排序并循环浏览所有附件,然后从独特的父母那里抓取第一个$limit。但这也会导致父母也有很多图像被选中常。)


    “当答案逃脱时,请更改问题......”

    我刚刚发布了a plugin,可以直接从媒体库批量选择“精选帖子图片”。我的功能核心从~45行到此;

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

    这不是随机的,但网站看起来更好,访问者现在可以更轻松地浏览内容,因为缩略图是一致的。

3 个答案:

答案 0 :(得分:0)

好。所以这是使用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可能没有任何孩子。

答案 1 :(得分:0)

这不是一个查询,但它比我之前发布的WordPress-hackery快得多,而且非常比原来慢得多。我认为这是付出正确性的代价,同时又是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;

基本上,首先抓住一个较大的结果集,并在类别中发布所有已发布的帖子。然后是一堆较小的查询,每个循环都会获取一个附件ID,直到$limit被填充。

如果你在这些类别中有很多帖子没有附件,你会在这里浪费一些时间。但在我们的情况下,它似乎是可控的。

仍在寻找有效的单一查询解决方案。 :)

答案 2 :(得分:0)

我解决了!今天重新发现了子查询和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;