Ist es möglich, alle Beiträge abzufragen, die keinen Anhang haben?

7

Ich möchte eine Liste aller Beiträge ohne Anhang erhalten und diese löschen.

Bei dieser Frage geht es darum, alle Beiträge zu erhalten, die einen Anhang haben, aber ich möchte das Gegenteil davon.

Die Brute-Force-Methode besteht darin, alle Pfosten zu erhalten und sie dann einzeln zu durchlaufen und dann zu überprüfen, ob sie Anhänge haben oder nicht. Aber ich möchte es nach Möglichkeit vermeiden.

Sudar
quelle

Antworten:

4

Ich wurde neugierig auf die SQL-Methode, um alle Beiträge ohne Anhänge zu finden.

Methode 1 - Unterabfrage mit NOT IN

Hier ist mein erster Versuch, eine solche Abfrage zu erstellen:

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

Dies ist der Abfrage von @ toscho sehr ähnlich, aber in der Syntax weniger rationalisiert ;-)

Methode 2 - LEFT JOINmitIS NULL

Diese Abfrage scheint auch zu funktionieren:

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

Hier verbinden wir die Posts-Tabelle mit sich selbst und nehmen dann die NULLZeilen in der übergeordneten Spalte der Anhänge auf.

Methode 3 - WP_Query mit dem posts_where-Filter, auch bekannt als Methode 1

Wir könnten das auch WP_Query()mit dem posts_whereFilter ändern :

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

wo:

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;
}
Birgire
quelle
Oh, ich habe das SQL-Update in der Frage nicht bemerkt. Sieht sehr ähnlich aus. @ toschos Version sieht schlanker aus ;-)
Birgire
2
Ich habe PHPMyAdmin ein paar Mal abgestürzt, als ich mit GROUP BY gespielt habe, also habe ich stattdessen DISTINCT verwendet ;-)
birgire
3
Ich kann dich leider nicht wieder hochstimmen :-). Aber ich mag Ihren zweiten Ansatz besser.
Pieter Goosen
1
@PieterGoosen danke, und es ist weniger Code ;-) @Sudar Ich habe eine weitere Möglichkeit mit einer LEFT JOINanstelle einer Unterabfrage hinzugefügt , aus irgendeinem Grund bin ich immer skeptisch gegenüber
Unterabfragen ;-)
1
@birgire Danke und ich habe dies als Antwort markiert. Ich mag den 2. und 3. Ansatz.
Sudar
5

Wenn Sie mit dem vollständigen Gegenteil der verknüpften Antwort vertraut sind, können Sie diese Abfrage einfach verwenden, um alle Beiträge mit einem Anhang abzurufen und ihre IDs als post__not_inParameter für Folgendes zu verwenden \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 );

Update Toscho hat mich darauf hingewiesen, diese eine Abfrage zu stellen. Und dies kann natürlich mit einer einfachen SQL-Abfrage erledigt werden:

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

Beachten Sie, dass dies etwas anders ist als die Variante aus der angegebenen Antwort, da diese Abfrage keinen Unterschied zwischen einem Bild und einem Post-Thumbnail macht und auch nach Anhängen jeglicher Art sucht.

David
quelle
Vielen Dank. Ich versuche im Allgemeinen, WP_Querymeine eigenen SQL-Anweisungen zu verwenden, anstatt sie zu schreiben, da dies der empfohlene Weg ist. Aber ich denke, dies ist ein Szenario, das komplex genug ist, um den Weg der SQL-Anweisung zu gehen.
Sudar