Well, let's take a look at mysqli_stmt_bind_param:
bool mysqli_stmt_bind_param ( mysqli_stmt $stmt , string $types , mixed &$var1 [, mixed &$... ] )
So, we see that the second parameter expects a string argument, and to elaborate this is "a string that contains one or more characters which specify the types for the corresponding bind variables".
Next, let's refer back to the warning message:
Warning: mysqli_stmt_bind_param() expects parameter 2 to be string, array given.
Yep, the warning message is confirmed by the PHP manual, and furthermore we have a hint as to what is wrong: an array was provided as the argument instead of a string.
Now, let's refer back to your code:
$where_clauses = $types = $values = [];
if (!empty($conditions)) {
foreach ($conditions as $clause => $condition) {
$where_clauses[] = $clause;
list($types[], $values[]) = $condition;
}
$query .= " AND ";
$query .= join(" AND ", $where_clauses);
}
echo $query;
$stmt = mysqli_prepare($sql_connect, $query);
if (!empty($conditions)) {
mysqli_stmt_bind_param($stmt, $types, $values);
}
Hence, we see that $types was initialised as an array, then within the foreach loop you append to $types. Consequently, $types is indeed an array, e.g., ['i', 'i', 'i'], whereas according to the PHP manual you want 'iii'. Thankfully, this is easily fixed by something like:
$types = implode('', $types);