web-dev-qa-db-fra.com

Est-il possible d'interroger toutes les publications qui n'ont pas de pièce jointe?

Je veux obtenir une liste de tous les messages qui n'ont pas de pièce jointe et les supprimer.

Cette question prend pour obtenir tous les messages que ont une pièce jointe, mais je veux le contraire.

La méthode la plus brutale est d’obtenir tous les messages, puis de les parcourir individuellement, puis de vérifier s’ils sont attachés ou non. Mais je veux l'éviter si possible.

7
Sudar

Je suis curieux de savoir comment SQL trouve toutes les publications sans pièce jointe.

Méthode n ° 1 - Sous-requête avec NOT IN

Voici ma première tentative de construire une telle requête:

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

Cela ressemble beaucoup à la requête de @ toscho, mais sa syntaxe est moins simplifiée ;-)

Méthode n ° 2 - LEFT JOIN avec IS NULL

Cette requête semble également fonctionner:

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

où nous joignons la table posts avec elle-même, puis prenons les lignes NULL dans la colonne parent des pièces jointes.

Méthode n ° 3 - WP_Query avec filtre posts_where aka méthode n ° 1

Nous pourrions également modifier la WP_Query() avec le filtre posts_where:

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

où:

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

Si vous êtes à l'aise avec l'opposé complet de la réponse liée, vous pouvez simplement utiliser cette requête pour extraire toutes les publications qui ont une pièce jointe, puis utiliser leurs identifiants comme paramètre post__not_in de \WP_Query:

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

Mise à jour Toscho m'a demandé de faire cette requête. Et, bien sûr, cela peut être géré avec une requête SQL simple:

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

Notez que cela diffère légèrement de la variante extraite de la réponse mentionnée, car cette requête ne fait aucune différence entre une image et une post-vignette et recherche également tout type de pièce jointe.

5
David