wordpresscustom-post-type

New REST API endpoint for Wordpress that uses WP_Query to search custom post type for matches


I'm trying to set up a new custom REST API endpoint for our wordpress site. I believe I have that part working correctly. The issue I cannot seem to figure out (even after extensive googling and asking Microsoft Copilot and Gitlab Duo Chat) is how to use WP_Query to successfully search for post types by passing a list of url parameters throught the REST API url.

This is what I have as of right now (all code in functions.php)

// Register new REST API route
add_action('rest_api_init', function () {
    register_rest_route('fx-product-search', '/products/search', array(
        'methods' => 'GET',
        'callback' => 'search_products',
        'permission_callback' => '__return_true',
    ));
});

function search_products($request) {
    
    $terms = $request->get_param( 'term' );
    $terms_array = explode(',', $terms);

    $args = array(
        'post_type' => 'fx-product', 
        'posts_per_page' => -1,
        's' => implode( ',', $terms_array),
        'compare' => 'LIKE',
        'sentence' => true,
        'suppress_filters' => true,
     );

    $query = new WP_Query($args);
    //return rest_ensure_response("WP_Query $args are: " . json_encode($args));
    
    $results = [];
    
    if ($query->have_posts()) {   
        //return rest_ensure_response(array('message' => 'have_posts is true.'));
        
        while ($query->have_posts()) {
            //return rest_ensure_response(array('message' => 'In while loop'));
            $query->the_post();
            $content = get_field('content', get_the_ID());
            $thumbnail_id = get_post_meta(get_the_ID(), 'product_image', true);
            $thumbnail_url = wp_get_attachment_url($thumbnail_id);
            $results[] = array(
                'id' => get_the_ID(),
                'title' => get_the_title(),
                'link' => get_permalink(),
                'content' => $content,
                'thumbnail' => $thumbnail_url,
            );
            
        }
                
    }
    
    // Reset post data
    wp_reset_postdata();
    // Return the response  

    if (empty($results)) {
        return rest_ensure_response(array('message' => 'No results found.'));
    } else {
        return rest_ensure_response($results);
    }

}

Note that I'm using the return rest_ensure_response lines as "quick and dirty" sanity checks. (I'm having trouble finding out where the debug and error logs are, or only my server guy can get them and I don't want to bug him every few mins.)

I've confirmed there are matching results on the site as well.

At the moment, it always says "No results found" when I hit a test url.

The goal is to have the REST API call work for URLs like this: (one term) .../products/search?term=SecretProduct

and this (multiple terms) .../products/search?term=Public Product 500,Copier 5000,Quick Print 400i

In the case of multiple terms, the terms would be comma separated but themselves may have spaces in them as shown above. Also, with mutliple terms, it should try to match with logical "OR".

Is this possible? I can get it work with one single word term.

Please advise. Thank you.


Solution

  • I have checked the code and found that the issue is appearing because in that code we are using s parameter for searching multiple terms while that parameter is taking those terms as string which causes this issue so need to create meta query by looping over the exploded term array so desired results can be achieved, so you need to replace the search_products function in your code.

    <?php
    function search_products( $request ) {
        
        $terms       = $request->get_param( 'term' );
        $terms_array = explode( ',', $terms );
        
        // We are using this to trim whitespace from each term we have exploded.
        $terms_array = array_map('trim', $terms_array);
    
        $args = array(
            'post_type'        => 'fx-product', 
            'posts_per_page'   => -1,
            'meta_query'       => array(
                'relation' => 'OR',
            ),
            'suppress_filters' => true,
        );
        // Here we are looping over each term to build meta query.
        foreach ( $terms_array as $term ) {
            $args['meta_query'][] = array(
                'key'     => 'content',  // Here we need to replace the ACF field key as per the need.
                'value'   => $term,
                'compare' => 'LIKE',
            );
        }
    
        $query   = new WP_Query($args);
        
        $results = [];
        
        if ( $query->have_posts() ) {   
            while ( $query->have_posts() ) {
                $query->the_post();
                $content       = get_field('content', get_the_ID());
                $thumbnail_id  = get_post_meta(get_the_ID(), 'product_image', true);
                $thumbnail_url = wp_get_attachment_url($thumbnail_id);
                $results[]     = array(
                    'id'        => get_the_ID(),
                    'title'     => get_the_title(),
                    'link'      => get_permalink(),
                    'content'   => $content,
                    'thumbnail' => $thumbnail_url,
                );
            }
        }
        
        wp_reset_postdata();
        
        if ( empty( $results ) ) {
            return rest_ensure_response( array( 'message' => 'No results found.') );
        } else {
            return rest_ensure_response( $results );
        }
    }