PHP Warning: Missing argument 2 for wpdb::prepare()
Hello plugin or theme author! You possibly found this post after searching the Internet for the error above: “PHP Warning: Missing argument 2 for wpdb::prepare().”
So, this is a new warning in 3.5. No sites are broken, everything is fine as before. But, this is indeed something you need to look at, because you may be exposing your users to a possible SQL injection vulnerability. Now that’s no fun!
First, if you’re a user and you want to get rid of these errors, you should turn off the displaying of errors in PHP. There are many ways to do this, such as in php.ini, .htaccess, etc. For this, you can just put this in wp-config.php. (Note that hiding errors on production sites is good practice anyway.)
If you’re a user, you can stop here. (If you need more help, please don’t comment here, try the helpful Support Forums.) Just be sure to send a link to this post to the developer of the theme or plugin referenced in the error.
Now, developers: Here’s how $wpdb->prepare() is supposed to work:
$wpdb->prepare( "SELECT * FROM table WHERE ID = %d AND name = %s", $id, $name );
See how $id — an integer, presumably — was passed as the second argument? That corresponds to the first placeholder, %d. Then, $name (a string) was passed as the third argument, thus the second placeholder, %s. This makes sure your query is safe, and prevents something like little bobby tables. (Note: the comic is wrong, don’t sanitize — always prepare your queries.)
The problem is, a number of people were calling $wpdb->prepare() with only one argument, like so:
$wpdb->prepare( "SELECT COUNT(*) FROM table" );
See, there’s no parameter (%d, %s, or for floats, %f) in this query. This happens to work fine, but the prepare call isn’t doing anything. You should instead the query directly, as there are no inputs.
But here’s where the problem lies:
$wpdb->prepare( "SELECT * FROM table WHERE id = $id" );
See the problem? That query isn’t secure! You may think you are “preparing” this query, but you’re not — you’re passing $id directly into the query, unprepared. And this, right here, is why $wpdb->prepare() now issues a warning if it isn’t called with more than one argument. Because you can’t prepare a query without more than one argument. Here’s a correct example:
$wpdb->prepare( "SELECT * FROM table WHERE id = %d", $id );
This wasn’t a decision done lightly. We don’t like shoving PHP warnings into the faces of users and developers. But given the potential security risks, we wanted everyone to immediately look at how they are running queries. And, of course, always prepare them properly.