I am receiving this notice when trying to use the $wpdb->prepare function:

Notice: wpdb::prepare was called incorrectly. The query does not contain the correct number of placeholders (7) for the number of arguments passed (4). Please see Debugging in WordPress for more information. (This message was added in version 4.8.3.) in C:\wamp\www\wpml\wp-includes\functions.php on line 4139

I looked at other posts on this topic and I don't see any of the same problems from those threads in my code. When developing this notice greatly slows down my application so I want to find a solution.

function get_meta_range($meta_key) {
    global $wpdb;

    // $meta_key = '_price'
    $include = '7275,7266,7256,7237,7196,7192,7164';

    $min = floor( $wpdb->get_var(
            SELECT min(meta_value + 0)
            FROM %1$s
            LEFT JOIN %2$s ON %1$s.ID = %2$s.post_id
            WHERE ( meta_key =\'%3$s\' OR meta_key =\'%4$s\' )
            AND meta_value != ""
            AND (
                %1$s.ID IN (' . $include . ')
        , $wpdb->posts, $wpdb->postmeta, $meta_key, '_min_variation' . $meta_key )
    ) );

    // $min = 15

Numbered placeholders don't work as you'd expect, and are going to be removed altogether at some point in the future, so should be considered invalid syntax.

So with this in mind, the error describes the problem- your query has 7 placeholders, but you only pass 4 values. For the repeated values, you just need to repeat them where you pass the substitutions.

  • 1
    Milo - I understand your answer but not sure on the syntax. Could you provide some example code to clarify? – Benjamin Dec 12 '17 at 4:34

The wpdb::prepare says that you should not quote placeholders, yet in your code there is:

WHERE ( meta_key =\'%3$s\' OR meta_key =\'%4$s\' )

Also keep in mind that the meta table is designed to be fast when you already know the post ID, and WP already fetches all of the meta when you grab a post.

So it would actually be much faster to use get_post_meta and calculate it in PHP, as the data has already been requested. Doing this query is both unnecessary, and potentially expensive

  • Tom - Can you provide some code to make what your saying more clear, not sure I understand. My code finds all available filtered posts within a range of min/max values based off the meta key, price in this case. The $include var holds the post ids I want to limit my query too. – Benjamin Dec 12 '17 at 4:43
  • @George you put quotes around your placeholders, e.g. \'%3$s\' versus %3$s. The docs explicitly say not to do this – Tom J Nowell Dec 12 '17 at 14:27
  • The first part about the quotes makes sense I was referring to the second part of your answer that mentioned the speed increase using a different technique then what I am using – Benjamin Dec 12 '17 at 22:18
  • You'd fetch all the post meta for the posts you want to test, then manually check the lowest and highest values. Think of it the same way as if someone gave you 12 books full of numbers and asked you to find the lowest and the highest, you'd open each book starting from the first page and going to the last page reading each number, and if the number is the highest of the lowest, you'd write it down as the new lowest, or the new highest. It's the same, but in PHP – Tom J Nowell Dec 13 '17 at 2:37
  • Are you saying calling get_post_meta for each post is faster than my query, don't think I understand your approach. A bit of code would really help make this more clear. – Benjamin Dec 13 '17 at 21:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.