Actualizar múltiples filas con $wpdb->update en WordPress usando IN como en SQL normal
Me preguntaba si es posible usar $wpdb->update
para actualizar valores en múltiples filas como con IN
en SQL "normal".
Quiero lograr algo como este ejemplo:
UPDATE [tabla]
SET [columna_1] = [valor_actualizado]
WHERE [columna_2] IN ([ids_separados_por_coma])
He estado buscando cómo funcionaría esto, pero aún no encuentro otra pregunta sobre esto o algún tipo de respuesta/publicación que explique si se puede hacer o no.
Por ahora estoy usando una consulta directa, pero sería mejor con una simple línea de código.

Como puedes ver en el código fuente el signo =
está codificado de forma fija en el método wpdb::update()
, por lo que, por defecto, no es posible usar IN
para el método de actualización.
La forma más sencilla de lograr esto es usando wpdb::query()
con tu consulta SQL, solo asegúrate de escapar correctamente todos los valores.
Ejemplo:
function wpdb_update_in( $table, $data, $where, $format = NULL, $where_format = NULL ) {
global $wpdb;
$table = esc_sql( $table );
if( ! is_string( $table ) || ! isset( $wpdb->$table ) ) {
return FALSE;
}
$i = 0;
$q = "UPDATE " . $wpdb->$table . " SET ";
$format = array_values( (array) $format );
$escaped = array();
foreach( (array) $data as $key => $value ) {
$f = isset( $format[$i] ) && in_array( $format[$i], array( '%s', '%d' ), TRUE ) ? $format[$i] : '%s';
$escaped[] = esc_sql( $key ) . " = " . $wpdb->prepare( $f, $value );
$i++;
}
$q .= implode( $escaped, ', ' );
$where = (array) $where;
$where_keys = array_keys( $where );
$where_val = (array) array_shift( $where );
$q .= " WHERE " . esc_sql( array_shift( $where_keys ) ) . ' IN (';
if( ! in_array( $where_format, array('%s', '%d'), TRUE ) ) {
$where_format = '%s';
}
$escaped = array();
foreach( $where_val as $val ) {
$escaped[] = $wpdb->prepare( $where_format, $val );
}
$q .= implode( $escaped, ', ' ) . ')';
return $wpdb->query( $q );
}
Luego úsalo así:
wpdb_update_in(
'posts', // tabla
array( 'post_author' => '1', 'post_status' => 'draft' ), // datos
array( 'post_author' => array( '2', '3', '4', '5' ) ), // where
array( '%d', '%s' ), // formato
'%d' // formato where
);
El SQL ejecutado será:
UPDATE wp_posts
SET post_author = 1, post_status = 'draft'
WHERE post_author IN (2, 3, 4, 5)

No he trabajado mucho en WP, así que no estaba al tanto del código fuente. Me aseguraré de guardarlo como referencia para el futuro. Me gusta tu solución y la marcaré como la respuesta.

Lo encontré útil, pero parece que algunas cosas han cambiado desde que se hizo esta respuesta. Primero, la firma de implode()
ha cambiado el orden de los parámetros desde PHP 7.4. Además, ¿no pude entender qué era $wpdb->$table
? Al final lo eliminé.

Las cosas han cambiado en 10 años, sí :)
$wpdb->$table
es la forma correcta de obtener el nombre completo de la tabla. No deberías usar, por ejemplo, "wp_content"
sino $wpdb->content
, porque el prefijo podría cambiar, y en multisitio cambiará definitivamente.
Esto no ha cambiado. Pero hoy tenemos el marcador %i
para escapar nombres de tablas.
Respecto a %f
, sí, eso se añadió relativamente hace poco junto con el %i
mencionado anteriormente.
