问题描述

我想得到所有没有附件的帖子的列表,并删除它们。

This question 需要获取所有附件的帖子,但我想要反过来。

强力的方法是获取所有帖子,然后单独循环,然后检查他们是否具有附件。但是如果可能,我想避免它。

最佳解决思路

我很好奇查找所有没有任何附件的帖子的 SQL 方式。

方法#1 – 使用 NOT IN 的子查询

这是我第一次尝试构建这样一个查询:

global $wpdb;
$sql = "
    SELECT  p1.ID, p1.post_title
    FROM    {$wpdb->posts} p1
    WHERE   p1.post_type = 'post'
        AND p1.post_status = 'publish'
        AND p1.ID NOT IN (
                SELECT DISTINCT p2.post_parent
                FROM {$wpdb->posts} p2
                WHERE p2.post_type = 'attachment' AND p2.post_parent > 0
        )
    ORDER BY p1.post_date DESC
";

// Fetch posts without attachments:
$posts_without_attachments = $wpdb->get_results( $sql );

// Display posts without attachments:
foreach( $posts_without_attachments as $post )
{
        echo $post->post_title . '<br/>';
}

这恰好与 @ toscho 的查询非常相似,但在语法中更加简化;-)

方法#2 – LEFT JOINIS NULL

这个查询似乎也可以工作:

global $wpdb;
$sql = "
    SELECT  p1.ID, p1.post_title
    FROM {$wpdb->posts} p1
    LEFT JOIN {$wpdb->posts} p2
    ON ( p2.post_parent = p1.ID AND p2.post_type = 'attachment' )
    WHERE p1.post_type =  'post'
    AND p1.post_status =  'publish'
    AND p2.post_parent IS NULL
    ORDER BY p1.post_date DESC
";

// Fetch posts without attachments:
$posts_without_attachments = $wpdb->get_results( $sql );

在那里我们自己加入帖子表,然后在附件的父列中选择 NULL 行。

方法#3 – WP_Query 与 posts_where 过滤器又名方法#1

我们也可以使用 posts_where 过滤器修改 WP_Query()

// Filter all posts without attachments:
add_filter( 'posts_where', 'wpse_no_attachments' );

// Query:
$q = new WP_Query( array( 'post_type' => 'post', 'posts_per_page' => -1 ) );

// Remove the filter:
remove_filter( 'posts_where', 'wpse_no_attachments' );

哪里:

function wpse_no_attachments( $where )
{
    global $wpdb;
    $where .= " AND {$wpdb->posts}.ID NOT IN (
                    SELECT DISTINCT wpse.post_parent
                    FROM {$wpdb->posts} wpse
                    WHERE wpse.post_type = 'attachment' AND wpse.post_parent > 0  ) ";
    return $where;
}

次佳解决思路

如果您对链接答案完全相反,您只需使用此查询即可获取具有附件的所有帖子,然后将其 ID 作为 WP_Querypost__not_in 参数:

$attachment_args = array(
  'post_type'      => 'attachment',
  'post_mime_type' => 'image',
  'post_status' => 'inherit',
  'posts_per_page' => -1,
  'post_parent__not_in' => array(0),
  'meta_query' => array(
    array(
      'key' => '_thumbnail_id',
      'value' => 'x',
      'compare' => 'NOT EXISTS'
    )
  ),
  'fields' => 'post_parent'
);
$atts = new WP_Query($args);
$parents = array_unique(wp_list_pluck($atts->posts,'post_parent'));

$post_args = array(
    'post_type'      => 'post',
    'posts_per_page' => -1
    'post__not_in'   => $parent
    'post_status'    => 'any'
);
// Posts with no attachment:
$post_query = new WP_Query( $post_args );

更新 Toscho 指出我做这个一个查询。而且,当然这可以用一个简单的 SQL Query 来处理:

<?php
$query = <<<SQL
    SELECT p.`ID` FROM {$wpdb->posts} p
    WHERE p.`post_type` = 'post'
    AND p.`post_status` = 'publish'
    AND p.`ID` NOT IN (
        SELECT DISTINCT a.`post_parent` FROM {$wpdb->posts} a
        WHERE a.`post_type` = 'attachment'
        AND a.`post_parent` != 0
    )
SQL;

//posts with no attachment
$results = $GLOBALS[ 'wpdb' ]->get_results( $query );

请注意,这与从参考答案中获取的变体略有不同,因为该查询在图像和 post-thumbnail 之间没有区别,并且还查找任何类型的附件。

参考文献

注:本文内容整合自 Google/Baidu/Bing 辅助翻译的英文资料结果。如果您对结果不满意,可以加入我们改善翻译效果:薇晓朵技术论坛。