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.
Je suis curieux de savoir comment SQL trouve toutes les publications sans pièce jointe.
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 ;-)
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.
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;
}
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.