wp query - WP_Query returns wrong post when searching by title?

admin2025-05-31  0

The comments left in my code explain what's going on.

protected function fetchLocationByTitle($title) {

    /*
     * The WP Query class returns wrong post when searching by title using the
     * structure below
     *
     * $query = new \WP_Query([
     *   'post_type' => 'location-data',
     *   'posts_per_page' => 1,
     *   'page' => 1, // Tried removing this per Tom Nowell's post, but still get wrong post.
     *   'post_status' => 'publish',
     *   'post_title' => $title
     * ]);
     *
     * So to work around we'll pull it ourselves
     */
    global $wpdb;

    // Changed to $wpdb->prepare per Tom Nowell's comment.
    $id = $wpdb->get_results($wpdb->prepare(
      "SELECT `ID` 
      FROM `wp_posts` 
      WHERE `post_title` = %s 
      AND `post_type` = 'location-data' 
      AND `post_status` = 'publish' 
      LIMIT 1", $title));
    if ($id && count($id)) {
      $id = $id[0]->ID;
      /*
       * With ID in hand we can pull a post object normally now.
       */
      return $this->parseLocation(\get_post($id));
    } else {
      return null;
    }
  }

Can anyone spot why it fetches a different post from the correct one I can get with my direct query?

The comments left in my code explain what's going on.

protected function fetchLocationByTitle($title) {

    /*
     * The WP Query class returns wrong post when searching by title using the
     * structure below
     *
     * $query = new \WP_Query([
     *   'post_type' => 'location-data',
     *   'posts_per_page' => 1,
     *   'page' => 1, // Tried removing this per Tom Nowell's post, but still get wrong post.
     *   'post_status' => 'publish',
     *   'post_title' => $title
     * ]);
     *
     * So to work around we'll pull it ourselves
     */
    global $wpdb;

    // Changed to $wpdb->prepare per Tom Nowell's comment.
    $id = $wpdb->get_results($wpdb->prepare(
      "SELECT `ID` 
      FROM `wp_posts` 
      WHERE `post_title` = %s 
      AND `post_type` = 'location-data' 
      AND `post_status` = 'publish' 
      LIMIT 1", $title));
    if ($id && count($id)) {
      $id = $id[0]->ID;
      /*
       * With ID in hand we can pull a post object normally now.
       */
      return $this->parseLocation(\get_post($id));
    } else {
      return null;
    }
  }

Can anyone spot why it fetches a different post from the correct one I can get with my direct query?

Share Improve this question edited May 22 at 16:35 Michael Morris asked May 22 at 13:00 Michael MorrisMichael Morris 11 bronze badge 5
  • note that esc_sql should never be used that way and doesn't work as an arbitrary SQL escaping function despite what its name suggests, you should instead be using wpdb->prepare to insert variables into SQL statements. Also when you say search, can you clarify if you're providing an exact match, or expecting it to find similar things? I also see your SQL statement does not specify page, page may be incorrect as the docs say: "Show the number of posts that would show up on page X of a static front page.", are you sure you didn't mean paged? I don't think it's necessary to specify – Tom J Nowell Commented May 22 at 13:33
  • $wp->prepare applied. Removing the $page argument has no effect - still pulls the wrong post. I am expecting an exact match or no match at all. This method is a fallback in case my users fail to explicitly link the post to its facility, which they've done on roughly half the pages. – Michael Morris Commented May 22 at 16:30
  • when you say it pulls in a post it shouldn't can you give examples of what you tried and what it gave instead? I wasn't aware it pulled in anything from reading your question, it looks like it gives zero results, not 1 incorrect result. Have you expanded posts_per_page to check if the result you want is found but not the first result? Have you checked for pre_get_post filters modifying the query variables? – Tom J Nowell Commented May 22 at 21:03
  • Without going into too much detail on the post details, the post it should be hitting has ID 84626, and the one it fetches through \WP_QUERY is id 91325. The two have nothing in common except their post_type – Michael Morris Commented May 23 at 11:36
  • see my updated answer, it should explain the difference – Tom J Nowell Commented May 23 at 14:55
Add a comment  | 

2 Answers 2

Reset to default 0

We should be able to fix the query by doing this instead:

$query = new \WP_Query([
  'post_type' => 'location-data',
  'posts_per_page' => 1,
  'post_status' => 'publish',
  'title' => $title
]);

This is because page is unnecessary and may not be the parameter you actually needed, paged would have been more appropriate, but it too is unnecessary.

Most importantly though, post_title is not a parameter of WP_Query according to the docs, instead it lists title. post_title is only mentioned as a parameter for search columns.

you can simply use get_posts() :

$posts = get_posts( [
  'title'          => $title,
  'post_status'    => 'publish',
  'post_type'      => 'location-data',
  'posts_per_page' => 1,
] );

https://developer.wordpress/reference/functions/get_posts/

转载请注明原文地址:http://conceptsofalgorithm.com/Algorithm/1748626063a313619.html

最新回复(0)