web-dev-qa-db-fra.com

Comment modifier cette requête $ wpdb pour accepter un tableau de statuts de publication

J'utilise cette fonction depuis ceci accepté réponse, qui obtient toutes les valeurs pour une clé de champ personnalisée (cross-post).

Comment pourrait-il être modifié pour permettre un tableau des statuts de publication?

function get_meta_values( $key = '', $type = 'post', $status = 'publish' ) {
    global $wpdb;

    if( empty( $key ) )
    return;

    $r = $wpdb->get_col( $wpdb->prepare( "
        SELECT pm.meta_value FROM {$wpdb->postmeta} pm
        LEFT JOIN {$wpdb->posts} p ON p.ID = pm.post_id
        WHERE pm.meta_key = '%s' 
        AND p.post_status = '%s' 
        AND p.post_type = '%s'
    ", $key, $status, $type ) );

    return $r;
}

par exemple quelque chose comme ça (ça ne marche pas)

function get_meta_values( $key = '', $type = 'post', $status = array( 'publish', 'draft' ) ) {
    global $wpdb;

    if( empty( $key ) )
    return;

    $r = $wpdb->get_col( $wpdb->prepare( "
        SELECT pm.meta_value FROM {$wpdb->postmeta} pm
        LEFT JOIN {$wpdb->posts} p ON p.ID = pm.post_id
        WHERE pm.meta_key = '%s' 
        AND p.post_status = '%s' 
        AND p.post_type = '%s'
    ", $key, $status, $type ) );

    return $r;
}
1
Andrew

Il suffit d'imploser le tableau passé:

function get_meta_values( $key = '', $type = 'post', $status = array( 'publish', 'draft' ) ) {
    global $wpdb;

    if( empty( $key ) )
        return;

    //First escape the status, since we don't use it with $wpdb->prepare()    
    $status = esc_sql( $status );

    //If its an array, convert to string
    if( is_array( $status ) ){
        $status = implode( ', ', $status ); //e.g. "publish, draft"
    }

    $r = $wpdb->get_col( $wpdb->prepare( 
        "SELECT pm.meta_value FROM {$wpdb->postmeta} AS pm
        LEFT JOIN {$wpdb->posts} p ON p.ID = pm.post_id
        WHERE pm.meta_key = %s
        AND p.post_status IN( {$status} ) 
        AND p.post_type = %s", 
        $key, $type ) );

    return $r;
}

Cela vous permet de passer $status sous forme de chaîne ou de tableau.

2
Stephen Harris

Utilisez l’opérateur IN pour les tableaux.

Lorsque vous utilisez $wpdb->prepare(), vous n'êtes pas obligé d'utiliser des guillemets autour de l'espace réservé à la chaîne %s. L'espace réservé à la chaîne sera cité automatiquement. C'est aussi la raison pour laquelle vous devez prendre des précautions lors de l'utilisation de $wpdb->prepare() avec l'opérateur IN si les valeurs du tableau sont des chaînes.

Ce premier exemple n'utilise pas les espaces réservés pour post stati mais les insère directement (séparés par des virgules et citées) dans la chaîne de requête

function get_meta_values( $key = '', $type = 'post', $status = array( 'publish', 'draft' ) ) {
    global $wpdb;

    if ( empty( $key ) ) {
        return;
    }

    // escape the status values
    $status = array_map( 'esc_sql', (array) $status );

    // $status_string: a comma separated string with quoted post stati
    // $status_string = "'publish', 'draft'";
    $status_string = "'" . implode( "', '", $status ) . "'";

    $query = "
        SELECT pm.meta_value FROM {$wpdb->postmeta} pm
        LEFT JOIN {$wpdb->posts} p ON p.ID = pm.post_id
        WHERE pm.meta_key = '%s'
        AND p.post_status IN ( $status_string )
        AND p.post_type = '%s'";

    $r = $wpdb->get_col( $wpdb->prepare( $query, $key, $type ) );

    return $r;
}

Ce deuxième exemple convertit le tableau avec la méthode de cette réponse https://stackoverflow.com/a/10634225

function get_meta_values( $key = '', $type = 'post', $status = array( 'publish', 'draft' ) ) {
    global $wpdb;

    if ( empty( $key ) ) {
        return;
    }

    // $status_string: a comma separated string with string placeholders (%s)
    // $status_string = "%s, %s";
    $status_string = implode( ', ', array_fill( 0, count( $status ), '%s' ) );

    //parameters array for call_user_func_array callback function $wpdb->prepare
    $prepare = array();

    // the query is the first parameter
    $prepare[] = "
        SELECT pm.meta_value FROM {$wpdb->postmeta} pm
        LEFT JOIN {$wpdb->posts} p ON p.ID = pm.post_id
        WHERE pm.meta_key = %s
        AND p.post_status IN ($status_string)
        AND p.post_type = %s
    ";

    // from here on out add to the $prepare array in the same order as inside the query
    $prepare[] = $key;

    foreach ( $status as $s ) {
        $prepare[] = $s;
    }

    $prepare[] = $type;

    // calling $wpdb->prepare() with the $prepare array
    $query = call_user_func_array( array( $wpdb, 'prepare' ), $prepare );

    $r = $wpdb->get_col( $query );

    return $r;
}

Remarque: les deux exemples doivent être codés de manière plus défensive (is_array (), etc.) s'ils sont utilisés en production.

2
keesiemeijer