最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Is it possible to query all posts that don't have an attachment?

programmeradmin2浏览0评论

I want to get a list of all posts that don't have an attachment and delete them.

This question takes about getting all posts that have an attachment, but I want the reverse of it.

The brute force way to do it is to get all posts and then loop through them individually and then check if they have attachement or not. But I want to avoid it if possible.

I want to get a list of all posts that don't have an attachment and delete them.

This question takes about getting all posts that have an attachment, but I want the reverse of it.

The brute force way to do it is to get all posts and then loop through them individually and then check if they have attachement or not. But I want to avoid it if possible.

Share Improve this question edited Apr 13, 2017 at 12:37 CommunityBot 1 asked Aug 25, 2014 at 8:58 SudarSudar 8091 gold badge11 silver badges24 bronze badges
Add a comment  | 

2 Answers 2

Reset to default 5

I got curious about the SQL way of finding all posts without any attachments.

Method #1 - Sub query with NOT IN

Here's my first attempt to construct such a query:

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/>';
}

This happens to be very similar to @toscho's query, but less streamlined in the syntax ;-)

Method #2 - LEFT JOIN with IS NULL

This query seems to work as well:

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 );

where we join the posts table with itself and then pick up the NULL rows in the attachments' parent column.

Method #3 - WP_Query with posts_where filter aka method #1

We could also modify the WP_Query() with the posts_where filter:

// 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' );

where:

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;
}

If you're comfortable with the complete opposite of the linked answer, you simply could use this query to fetch all posts that have an attachment and then use their IDs as the post__not_in parameter of \WP_Query:

$attachment_args = [ 
  'post_type'      => 'attachment',
  'post_mime_type' => 'image',
  'post_status' => 'inherit',
  'posts_per_page' => -1,
  'post_parent__not_in' => [0],
  'meta_query' => [
    [
      '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 = [
    '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 );

Update: Fuxia pointed me to make this one query. And, of course, this can be handled with one plain 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 );

Note that this is slightly different to the variant taken from the referred answer as this query make no difference between an image and a post-thumbnail and also looks for any type of attachments.

发布评论

评论列表(0)

  1. 暂无评论