Leave a Reply

3 comments

  1. I am just incredible stupid here as this can be easily done by a simple WP_Query:

    
    new WP_Query( array( 'post_type' => 'shop_order', 'meta_key' => $meta_key, 'meta_value' => $meta_value ) )
    

    However, I decided to compare the actual generated SQL of the get_posts() with a ‘post_where’ filter solution which is:

    
    SELECT wp_posts.ID FROM wp_posts  WHERE 1=1  AND wp_posts.post_type = 'engine' AND ID IN (SELECT post_id FROM wp_postmeta WHERE meta_key = "horsepower" AND meta_value = "275")  ORDER BY wp_posts.post_date DESC LIMIT 0, 5
    SELECT wp_posts.* FROM wp_posts WHERE ID IN (361,327)
    SELECT post_id, meta_key, meta_value FROM wp_postmeta WHERE post_id IN (327,361)
    

    with the actual generated SQL of the new WP_Query() solution which is:

    
    SELECT SQL_CALC_FOUND_ROWS  wp_posts.ID FROM wp_posts  INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id) WHERE 1=1  AND wp_posts.post_type = 'engine' AND (wp_posts.post_status = 'publish' OR wp_posts.post_author = 1 AND wp_posts.post_status = 'private') AND ( (wp_postmeta.meta_key = 'horsepower' AND CAST(wp_postmeta.meta_value AS CHAR) = '275') ) GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC LIMIT 0, 10
    SELECT FOUND_ROWS()
    SELECT wp_posts.* FROM wp_posts WHERE ID IN (361,327)
    SELECT post_id, meta_key, meta_value FROM wp_postmeta WHERE post_id IN (327,361)
    

    So, both solutions are roughly equally efficient (the WP_Query() solution is probably slightly faster) but certainly not as efficient as human generated SQL.

  2. function get_post_by_meta_value( $meta_key, $meta_value ) {
      $post_where = function ($where) use ( $meta_key, $meta_value ) {
        global $wpdb;
        $where .= ' AND ID IN (SELECT post_id FROM ' . $wpdb->postmeta
          . ' WHERE meta_key = "' . $meta_key .'" AND meta_value = "' . $meta_value . '")';
        return $where;
      };
      add_filter( 'posts_where', $post_where );
      $args = array(
        'post_type' => 'shop_order',
        'post_status' => 'published',
        'post_per_page' => -1,
        'suppress_filters' => FALSE
      );
      $posts = get_posts( $args );
      remove_filter( 'posts_where' , $posts_where );
      return $posts;
    } 
    

    get_post_by_meta_value() returns an array of all posts of the specified post_type which have the specified meta_value for the specified meta_key which will be a 1 element array if the meta_value is unique.