Warning: Missing argument 2 for wpdb::prepare() on theme functions - php

I upgraded my old site from wordpress version 3.4 to 4.4 recently. Suddenly I am getting a PHP warning as per below:
Warning: Missing argument 2 for wpdb::prepare(), called in ...../wp-content/themes/...functions/admin-functions.php on line 1543 and defined in .......public/wp-includes/wp-db.php on line 1246
Below are the codes for admin-functions.php:
global $wpdb;
$query = "SELECT *,count(*) AS used FROM $wpdb->postmeta WHERE meta_key = '_wp_page_template' AND meta_value = '$filename' GROUP BY meta_value";
$results = $wpdb->get_row($wpdb->prepare($query),'ARRAY_A'); // Select thrid coloumn accross
if(empty($results))
return false;
and wp-db.php
public function prepare( $query, $args ) {
if ( is_null( $query ) )
return;

You need to use placeholders and add the variable as an argument to prepare,%s is a placeholder for string value,assuming it is string from your quotes
$query = "SELECT *,count(*) AS used FROM $wpdb->postmeta
WHERE meta_key = '_wp_page_template' AND meta_value = %s
GROUP BY meta_value";
$results = $wpdb->get_row($wpdb->prepare($query,$filename),'ARRAY_A'); // Select thrid coloumn accross

I would recommend reading the documentation for $wpdb->prepare.
Prepare requires at least two arguments to be passed in. The first is the query, using placeholders (%s for a string and %d for a number), and the second is the list of variables / values to place into the query instead of the placeholders.
For your specific case, I'm demonstrating in a bit longer format so you can see clearly:
global $wpdb;
// Old query. Let's get it ready for prepare...
// $query = "SELECT *,count(*) AS used FROM $wpdb->postmeta WHERE meta_key = '_wp_page_template' AND meta_value = '$filename' GROUP BY meta_value";
// New query, ready for prepare:
$query = "SELECT *,count(*) AS used FROM $wpdb->postmeta WHERE meta_key = %s AND meta_value = %s GROUP BY meta_value";
// Now we pass that into prepare, along with the two values we want replaced
$wpdb->prepare($query, '_wp_page_template', $filename);
// And we execute the query...
$results = $wpdb->get_row($query,'ARRAY_A');
Note that you can use the placeholders for as many values as you want, but the idea is that you use them for any value that is user input. If the value may be posted through a form, for example, you absolutely want to use prepare on that value. Example:
$post_id = $_POST['post_id'];
$query = 'SELECT * FROM $wpdb->postmeta WHERE post_id = %d';
$query = $wpdb->prepare($query, $post_id);
Hopefully this helps!

You need to pass $meta_key as second argument.
eg:-
<?php
// set the meta_key to the appropriate custom field meta key
$meta_key = 'miles';
$allmiles = $wpdb->get_var( $wpdb->prepare(
"
SELECT sum(meta_value)
FROM $wpdb->postmeta
WHERE meta_key = %s
",
$meta_key
) );
echo "<p>Total miles is {$allmiles}</p>";
?>
so here your second second argument is $filename.
Reference :- Class Reference / wpdb

Related

wpdb::prepare() with use multi placeholders (args)

I want to query all user roles "subscriber" or "administrator"
$ARRAY = array('%subscriber%','%administrator%');
$query = $wpdb->prepare( "
SELECT *
FROM {$wpdb->usermeta}
WHERE meta_value IN %s
ORDER BY user_id
DESC LIMIT {$limit} OFFSET {$offset}
", $ARRAY );
Errors: Notice: wpdb::prepare was called incorrectly. The query only expected one placeholder, but an array of multiple placeholders was sent.
I want to use multi placeholders, how to fix? thank you!
Using LIKE operator and AND condition in place of IN() function.
You can try:
$ARRAY = array('%subscriber%','%administrator%');
$query = $wpdb->prepare( "
SELECT *
FROM {$wpdb->usermeta}
WHERE meta_value LIKE %s OR meta_value LIKE %s
ORDER BY user_id
DESC LIMIT {$limit} OFFSET {$offset}
", $ARRAY );
You need to expand the array into a string by using the implode function as it's expecting a string to be passed.
$ARRAY = array('%subscriber%','%administrator%');
$array_placeholders = implode( ', ', array_fill( 0, count( $ARRAY ), '%s' ) );
$query = $wpdb->prepare( "
SELECT *
FROM {$wpdb->usermeta}
WHERE meta_value IN ( $array_placeholders )
ORDER BY user_id
DESC LIMIT {$limit} OFFSET {$offset}
", $ARRAY );
First, I should point out a security problem with your query. You are looking for any meta value with the words "subscriber" and "administrator" in them. So with any user account on your site, I could just set my first name or bio to contain "administrator" and your query will pick me up as one. If you are looking for roles, make sure you are explicit about it:
$prefix = $wpdb->get_blog_prefix();
... "WHERE meta_key = '{$prefix}_capabilities' AND " ...
Second, although incorrect, Andrew's answer looks better, because you're not hard-coding the number of roles you're going to look for in the query itself, like in Karlo's answer. Imagine you have to query for 15 roles. The reason it's incorrect though, is because the capabilities meta value is a serialized PHP array, so you can't really use IN() there, unfortunately, but using the same idea, you could do something like this:
$prefix = $wpdb->get_blog_prefix();
$roles = array( 'subscriber', 'administrator' );
$parts = array();
foreach ( $roles as $role ) {
$parts []= $wpdb->prepare( "meta_value LIKE %s",
'%' . $wpdb->esc_like( $role ) . '%' );
}
$parts_sql = implode( " OR ", $parts );
$sql = "SELECT * FROM {$wpdb->usermeta}
WHERE meta_key = '{$prefix}capabilities'
AND ({$parts_sql})";
$wpdb->get_results( $sql, ARRAY_A );
Finally, even if you do get site administrators this way, make sure you don't allow them any actions just based on their roles, and run capability checks wherever applicable with current_user_can() or user_can().
Hope that helps.

Getting 'meta_value' when searching for matching 'post_id' and 'meta_key', 'meta_value' combo

postmeta table example
The end result is matching an array of 'post_id', sorted by the number of attendees. I know it is a WP backend but I have to do it in SQL, no 'get_posts' or anything WordPress related. What I'm wanting to do is confusing so I'll try to be clear.
What I Have To Begin:
$check_post_ids - the original array of post_ids I need to check
$start_date - the 'meta_value' each event's '_StartDate' needs to match.
What I Need To Do:
I need to check these three post_ids to see if they have a matching start date. If they do, I need to get an array of post_ids sorted from the highest to lowest number of attendees.
Currently I was planning on doing this with multiple SELECTs and foreach() statements, but I feel like there has to be a simpler way to do this ( i.e. One SELECT & foreach() ). Here's what I'm doing at the moment. I haven't finished it yet because I feel like there has to be a simpler way to do this. Newer to SQL and any help is tremendously appreciated!
$check_post_ids = array('484', '627', '982', '2435');
$start_date = '1963-10-20 19:30:00';
// iterate through array of post_ids and check if they have the same _StartDate
foreach($check_post_ids as $id){
$start_date_check = "SELECT * FROM `wp_postmeta` WHERE `post_id` =" . $id . " AND `meta_key` LIKE '_StartDate' AND `meta_value` = '" . $start_date . "'";
$start_date_check_result = mysqli_query($conn, $start_date_check);
// assign all post_ids with a matching _StartTime to a new array
if (mysqli_num_rows($start_date_check_result) > 0) {
while($row = mysqli_fetch_assoc($start_date_check_result)) {
$matching_post_ids[] = $row['post_id'];
// iterate through matching_post_ids array, get the _NumAttendees for each, and assign their id and _NumAttendees to an assoc array to be sorted
foreach($matching_post_ids as $id){
$attendees_check = "SELECT meta_value FROM wp_postmeta WHERE post_id = " . $id . " AND meta_key = '_ecp_custom_2'";
$attendees_check_result = mysqli_query($conn, $attendees_check);
if($upvotes_check > 0){
while($row = mysqli_fetch_assoc($attendees_check_result)){
$sort_by_attendees['id'] = $id;
$sort_by_attendees['attendees'] = $row['meta_value'];
$sort_by_attendees_array[] = $sort_by_attendees;
}
}
}
For the first part of the query, I think you can simplify your code by using SQL IN keyword. Basically it substitutes the role of your first array with all your post IDs. Then, you can write a SQL query like this :
SELECT meta_value
FROM wp_postmeta
WHERE meta_key = '_ecp_custom_2'
AND post_id IN (SELECT post_id
FROM wp_postmeta
WHERE post_id IN ('484', '627', '982', '2435')
AND meta_key LIKE '_StartDate'
AND meta_value = '" . $start_date . "'")
ORDER BY meta_value DESC
There are 2 queries. The first one in the parenthesis, subselect all the post ids on your table wp_postmeta where post_ids have ids in your list and if they match with your starting date. Then, the main query selects all meta_values (I suppose attendees) based on your first subquery (all post ids with your starting date).
Hope it will help you.

PHP/MySql search array with array

I'm building a WordPress website.
With a MySql Query I load all companies from my database that have a specific brand:
$results = $wpdb->get_results("SELECT * FROM $wpdb->postmeta WHERE meta_key = 'brand'")`
brand is an array so I search for a specific value in array:
$brand = $_GET['brand'];
$brandNeedle = $brand;
if(in_array($brandNeedle, $brand[0]))
Now, my client asked to list all users that are connected to all those companies that are selected.
So I need to create a new query. Fortunately the users all have a field added to their colum that tells me where they are working.
So I thought: what if I create a array that holds all companynames that are queried from the companylist.
With this array I can select all users who have the company name in their column
So I think the query should be something like this:
SELECT * FROM $wpdb->usermeta WHERE meta_key='company' AND meta_value ='THE ARRAY'
But this doesn't work obvious because it can't search with an array in an array.
I can't seem to figure it out. Any ideas?
-- EDIT --
Okay so I did the implode function and I do something wrong:
$brand_array = array();
for($i=0; $i <count($results); $i++){
$result = $results[$i];
if ($i % 2 == 0){
$oddeven = 'even';
}else{
$oddeven = 'odd';
}
$post_id = $result->post_id;
$company_name = get_post_meta($post_id, 'company_name', true);
$brand_array[] = $company_name;
}
print_r($brand_array);
$imploded = implode(',',$brand_array);
$query = "SELECT * FROM $wpdb->usermeta WHERE meta_key='company' AND meta_value IN $imploded";
$persons = $wpdb->get_results($query);
This gives me the results I need (the two companies in a new array)
and gives me the following error:
WordPress database error: [You have an error in your SQL syntax; check the manual that
corresponds to your MySQL server version for the right syntax to use near
'brand1,brand2' at line 1]
SELECT * FROM wp_usermeta WHERE meta_key='company' AND meta_value IN
brand1,brand2
Have you thought about using the "IN" clause on MySQL?
https://dev.mysql.com/doc/refman/5.0/en/comparison-operators.html#function_in
You would probably have something like:
$query = "SELECT * FROM ".$wpdb->usermeta." WHERE meta_key='company' AND meta_value IN ('".implode("', ', $brand)."')";
(edit: forgot to add the parenthesis around the "in" content)
Search for mysql for IN clause
SELECT * FROM $wpdb->usermeta WHERE meta_key='company' AND meta_value IN implode(',',$brand_array)

Getting a single MYSQL result where the field is an array

Wordpress database, bit stuck on this one.
I'm using the following to get the ID of the current user.
$user_ID = get_current_user_id();
This returns something like this :
15
Now I try to find the matching value of $user_ID in the field show_user_list The data in this field is stored in an array.
Which looks something like this :
a:2:{i:0;s:2:"29";i:1;s:2:"15";}
This is the query i'm running (along with a set of conditions) :
global $wpdb; $result = $wpdb->get_results( "SELECT post_id FROM wp_postmeta WHERE show_user_list IN (' . implode(',', $user_ID) . ' AND post_type = 'show' AND post_status = 'publish'" );
And then I'm trying to echo the value of the matching post_id with this :
foreach ( $result as $unique ) {
echo $unique->post_id;
}
But it's not returning anything. I know I must be making a mistake while dealing with the array but I don't know where I'm going wrong?
looks like you have stored a serialized array in the show_user_list field, so it will be a hustle to search for values into using a db query.
In the model you described, you have to select all the rows from wp_postmeta that match "post_type = 'show' AND post_status = 'publish'", then manually filter results that do not have the user id in the unserialized show_user_list field.
You might try something like :
in_array($user_ID, unserialize($row->show_user_list))
Also, I noticed multiple errors in your query: string not properly concatenated with PHP code and the right parenthesis of the IN clause not closed.
Regards,
same
EDIT
Here is how I would solve your problem providing info you have given :
$user_ID = get_current_user_id();
global $wpdb;
$results = $wpdb->get_results("SELECT post_id, show_user_list FROM wp_postmeta WHERE post_type = 'show' AND post_status = 'publish'");
$user_post_ids = array();
foreach ($results as $post) {
if (in_array($user_ID, unserialize($post->show_user_list))) {
$user_post_ids[] = $post->post_id;
}
}
Hope this helps !

WordPress custom SQL

I have this function which contains some custom SQL:
function user_comment_count_by_meta( $user_id, $meta_key )
{
global $wpdb;
$count = 0;
$sql = "SELECT count(*) FROM $wpdb->comments comments INNER JOIN $wpdb->commentmeta meta ON comments.comment_ID = meta.comment_id WHERE comments.user_id = %d AND meta.meta_key = %s";
$count = $wpdb->get_var( $wpdb->prepare( $sql, $user_id, $meta_key ) );
return $count;
}
What it should be doing is counting all the comments for a user that have a particular meta value attached to them and returning that number. So for example if a user has made 20 comments and then 11 of those have the meta value 'accepted' attached to them then the number returned would be 11.
I call the function like so:
<?php $count = user_comment_count_by_meta( get_the_author_meta('id'), 'accepted' ); ?>
However it doesn't return anything. Not sure where I have gone wrong? If any SQL geniuses could help or if anyone can spot a problem it'd be much appreciated. Thanks.
Well,I think that the SQL it's ok, but when you call your function you are using
get_the_author_meta('id')
and this function I think that have other meaning.
If you want the ID from the post author you must use:
get_the_author_ID()
I'm not sure. really.

Categories