WordPress как на ладони
Недорогой хостинг для сайтов на WordPress: wordpress.jino.ru

Замена $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.0
 */
function wpdb_update( $table, $data, $where ){
	global $wpdb;

	if ( ! is_array( $data ) || ! is_array( $where ) )
		return false;

	$SET = $WHERE = [];

	// 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 ] );

Так гораздо удобнее и понятнее.

5 комментов
  • @ mihdan409 cайт: www.kobzarev.com

    А почему отдельной функцией? Можно, например, на хуке init расширить сам $wpdb.

    Ответить26 дней назад #
    • Kama7376

      Как? Там вроде бы переподключаться надо будет, не круто тоже.

      2
      Ответить24 дня назад #
      • @ mihdan409 cайт: www.kobzarev.com

        Простым способом, согласен, не сделать, можно только костылём расширить методы.

        Ответить23 дня назад #
Здравствуйте, !     Войти . Зарегистрироваться