| @@ -1195,9 +1195,12 @@ | ||
| 1195 | 1195 | * |
| 1196 | 1196 | * @return mixed bool|results. |
| 1197 | 1197 | */ |
| 1198 | 1198 | public function add_client_field( $field ) { |
| 1199 | - if ( ! empty( $field['field_name'] ) && isset( $field['client_id'] ) ) { | |
| 1199 | + // "0" is a name the column stores, so the write is refused only for a name that is missing | |
| 1200 | + // or empty, not for every name PHP reads as falsy. A name that is not a string is refused | |
| 1201 | + // outright: false is set and is not '', and it would reach the column as an empty name. | |
| 1202 | + if ( isset( $field['field_name'] ) && is_string( $field['field_name'] ) && '' !== $field['field_name'] && isset( $field['client_id'] ) ) { | |
| 1200 | 1203 | if ( $this->get_client_fields_by( 'field_name', $field['field_name'], $field['client_id'] ) ) { // field name existed for the client can not create. |
| 1201 | 1204 | return false; |
| 1202 | 1205 | } |
| 1203 | 1206 | if ( $this->wpdb->insert( $this->table_name( 'wp_clients_fields' ), $field ) ) { |
| @@ -1217,9 +1220,11 @@ | ||
| 1217 | 1220 | * |
| 1218 | 1221 | * @return mixed|false field. |
| 1219 | 1222 | */ |
| 1220 | 1223 | public function update_client_field( $field_id, $field ) { |
| 1221 | - if ( $field_id && ! empty( $field['field_name'] ) ) { | |
| 1224 | + // Same as the add above: a rename to "0" is a rename, not a name left out, and a name that | |
| 1225 | + // is not a string would be written over the stored name as an empty one. | |
| 1226 | + if ( $field_id && isset( $field['field_name'] ) && is_string( $field['field_name'] ) && '' !== $field['field_name'] ) { | |
| 1222 | 1227 | $current = $this->get_client_fields_by( 'field_id', $field_id ); |
| 1223 | 1228 | if ( $current && $this->wpdb->update( $this->table_name( 'wp_clients_fields' ), $field, array( 'field_id' => $field_id ) ) ) { |
| 1224 | 1229 | return $this->get_client_fields_by( 'field_id', $current->field_id ); |
| 1225 | 1230 | } |
| @@ -1273,9 +1278,15 @@ | ||
| 1273 | 1278 | * @return mixed|null $field field data. |
| 1274 | 1279 | */ |
| 1275 | 1280 | public function get_client_fields_by( $by = 'field_id', $value = null, $client_id = 0 ) { |
| 1276 | 1281 | |
| 1277 | - if ( empty( $by ) || empty( $value ) ) { | |
| 1282 | + // "0" is a name the column stores, so a falsy test here would make a field named "0" unfindable | |
| 1283 | + // and let a second one be created under the same name. Only the name lookup takes that | |
| 1284 | + // exception: every other column keeps refusing a falsy value, so a client_id of 0 stays "no | |
| 1285 | + // client" instead of matching every general field. | |
| 1286 | + $missing = 'field_name' === $by ? ( null === $value || '' === $value ) : empty( $value ); | |
| 1287 | + | |
| 1288 | + if ( empty( $by ) || $missing ) { | |
| 1278 | 1289 | return null; |
| 1279 | 1290 | } |
| 1280 | 1291 | |
| 1281 | 1292 | $sql = ''; |
| @@ -1376,8 +1387,15 @@ | ||
| 1376 | 1387 | // Handle search. |
| 1377 | 1388 | if ( isset( $params['search'] ) && ! empty( $params['search'] ) ) { |
| 1378 | 1389 | $search_term = $this->escape( htmlspecialchars( $params['search'] ) ); |
| 1379 | 1390 | $where .= ' AND clients_fields.field_name LIKE "%' . $search_term . '%"'; |
| 1391 | + } | |
| 1392 | + | |
| 1393 | + // Handle exact field name. The value is queried as it is stored, with no bracket stripping, so | |
| 1394 | + // the column collation decides equality the same way the unique index does. An empty string | |
| 1395 | + // filters on an empty name; pass null to leave the filter off. | |
| 1396 | + if ( isset( $params['field_name_exact'] ) && is_string( $params['field_name_exact'] ) ) { | |
| 1397 | + $where .= $this->wpdb->prepare( ' AND clients_fields.field_name = %s', $params['field_name_exact'] ); | |
| 1380 | 1398 | } |
| 1381 | 1399 | |
| 1382 | 1400 | // Handle client id. |
| 1383 | 1401 | if ( isset( $params['client_id'] ) && ! empty( $params['client_id'] ) ) { |