$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 ] );
Так гораздо удобнее и понятнее.