$wpdb->update, где в значении параметра $where можно указать массив
Указанное значение для $where поля превратиться в IN ( значения массива через запятую ) при запросе.
В WordPress в методе $wpdb->update в значении поля в параметре $where нельзя указать массив, чтобы он превратился в IN часть запроса. И это неудобно!
Покажу на примере, о чем идет речь.
Допустим, у нас есть массив с ID постов: [ 1, 5, 9 ] и нам нужно всем этим постам обновить поле post_status, установить туда статус draft.
Обычно в WordPress эта задача решается через $wpdb->query и написание отдельного запроса:
$post_ids = [ 1, 5, 9 ];
$wpdb->query(
"UPDATE $wpdb->posts SET post_status = 'draft'
WHERE ID IN (". implode(',', array_map('intval',$post_ids) ) .")"
);
Как можно видеть из примера, запрос не особо читаемый и в нем легко можно допустить ошибку. И это при том, что тут нужно обновить всего одно поле, и в WHERE части также указывается всего одно поле. Если добавить еще полей, то запрос станет еще менее читаемый.
Было бы гораздо удобнее, если бы можно было сделать так:
$post_ids = [ 1, 5, 9 ]; $wpdb->update( $wpdb->posts, [ 'post_status'=>'draft' ], [ 'ID'=>$post_ids ] );
Предлагаю небольшую функцию wpdb_update()
Функция полностью заменяет $wpdb->update(). В ней можно указывать массив в качестве значений поля в параметре $where.
Функцию я упростил: убрал от туда параметры форматов. Все передаваемые данные интерпретируются как строки. Числа автоматически превратятся в числа во время SQL запроса. С таким подход я багов пока не встречал, поэтому не вижу тут проблемы.
/**
* Update a row in the table
*
* Extends basic $wpdb->update to allow pass array in value of $where field array. Passed array become `IN ()` sql statement.
*
* $wpdb->update( 'table', [ 'column' => 'foo', 'field' => 1337 ], [ 'ID' => [1,3,5] ] )
*
* @param string $table Table name
* @param array $data Data to update (in column => value pairs).
* Both $data columns and $data values should be "raw" (neither should be SQL escaped).
* Sending a null value will cause the column to be set to NULL.
* @param array $where A named array of WHERE clauses (column => value).
* value can be an array, it becomes `IN ()` sql statement in this case.
* Multiple clauses will be joined with ANDs.
* Both $where columns and $where values should be "raw".
* Sending a null value will create an IS NULL comparison.
*
* @return int|bool Number of rows affected/selected for all other queries. Boolean false on error.
* @see wpdb::update() https://wp-kama.ru/filecode/wp-includes/wp-db.php#L2214-2255
* @author Kama
* @ver 1.1
*/
function wpdb_update( $table, $data, $where ){
global $wpdb;
if( ! is_array( $data ) || ! is_array( $where ) ){
return false;
}
$SET = [];
foreach( $data as $field => $value ){
$field = sanitize_key( $field );
if( is_null( $value ) ){
$SET[] = "`$field` = NULL";
continue;
}
$SET[] = $wpdb->prepare( "`$field` = %s", $value );
}
$WHERE = [];
foreach( $where as $field => $value ){
$field = sanitize_key( $field );
if( is_null( $value ) ){
$WHERE[] = "`$field` IS NULL";
continue;
}
if( is_array( $value ) ){
foreach( $value as & $val ){
$val = $wpdb->prepare( "%s", $val );
}
unset( $val );
$WHERE[] = "`$field` IN (" . implode( ',', $value ) . ")";
}
else {
$WHERE[] = $wpdb->prepare( "`$field` = %s", $value );
}
}
$sql = "UPDATE `$table` SET " . implode( ', ', $SET ) . " WHERE " . implode( ' AND ', $WHERE );
return $wpdb->query( $sql );
}
Теперь задачу описанную выше можно решить таким кодом:
$post_ids = [ 1, 5, 9 ]; wpdb_update( $wpdb->posts, [ 'post_status'=>'draft' ], [ 'ID'=>$post_ids ] );
Так гораздо удобнее и понятнее.