Hi @atakanau,
Using %1s is not recommended (or supported by wpdb::prepare()) for this, as it’s actually bypassing the entire purpose of using prepared queries.
Furthermore %1s is actually saying “Print %s with at least 1 character”, not the same as %1$s which is “The first argument presented as a string”. wpdb::prepare() accepts %1s for backwards compatibility with old code, but it should not be used intentionally.
This code is the same syntactically as what you’re currently using: (which has no SQLi prevention in place)
$ids = implode(',',$id_arr);
$wpdb->query( $wpdb->prepare( "SELECT ... WHERE ID IN( $ids ) " ) );The proper way to achieve what you want, would be to apply some sanitization to the input before interpolating:
$ids = implode( ',', array_map( 'intval', $id_arr ) );
$wpdb->get_results( "SELECT ... WHERE ID IN( $ids ) " );You’ll find many examples of this in WordPress files, such as WP_Query:
NOTE: If you’re looking to use strings rathe than IDs, you’d have to do something like this to properly escape each piece:
$slugs=""" . implode( '" , "', array_map( 'esc_sql', $slugs ) ) ) ) . '"';
$wpdb->get_results( "SELECT ... WHERE post_name IN( $slugs ) " );
There’s other approaches to this, like using array_fill() to generate the placeholders: https://stackoverflow.com/a/38735186
There’s work to support list notation with WordPress’s prepared statements in this trac ticket: https://core.trac.projectdmc.org/ticket/54042
