SearchWP Results In WooCommerce Product & Variation REST API Search

There’s a super nifty extension out there to give SearchWP it’s own REST API endpoint and it’s super useful! It’s made by my good friends at Caldera Forms and it may just solve your needs.  But it wasn’t helping me solve a problem I had.  On a project I have a very customized hooked into and filtered situation going on with the WooCommerce products endpoint on the API.  I didn’t want to refactor to work with that plugin so I needed to get results going into the primary products endpoint we are already using.

?search=keyword

To use the default WordPress search functionality in an API endpoint you tack on ?search=keyword.  This is cool and all but we are implementing SearchWP.  SearchWP works by intercepting WP_Query when it’s got the ‘is_search’ set.  It then does it’s own thing and returns the results.

The issue is, it doesn’t intercept when doing a search through the REST API.  Why? I forgot, I dug through code for hours and figured it out but I can’t remember or sum up the reason so I’m just going to give my solution.

Pass Along IDs From SWP_Query

First thing you will want to do is hook into pre_get_posts and inject SWP_Query search results into the query’s ‘post__in’ parameter.  You need to also tell the query it’s not a search and be sure you are even in the right place to be doing this.  Here’s a quick gist

https://gist.github.com/ChrisFlannagan/7c0ae5510482a9cea9fb488c7f088fca

Order By Post__In

We can’t just let this go and it will work.  The query may still try to order by something other than the result of IDs we got from SearchWP.  So we need to hook into rest_{post_type}_query.  Here’s the gist of that.

https://gist.github.com/ChrisFlannagan/42488c578c3a9167ee2a7290f937d358

Yoast Primary Category Endpoint for the WP REST API

I had a special case today where I needed to pull in posts specifically from a Yoast SEO Plugin‘s primary category.  Yoast SEO allows you to set a single, primary category for a post in WordPress.  This is an awesome feature and very useful.

A site I’m building right now uses the API to pull in the latest articles of a category in a big drop down hero navigation system.  The thing is, just pulling from a category gets a lot of the same articles when clicking around the different category options.  We wanted to pull by primary category so each click gives a unique set of posts that are very relevant to the category option.

The Struggle

There may be a super simple way to do this already but I was seriously struggling googling for the answer.  I’ve done some extending of the WP REST API but I’m still a novice so I was hoping to avoid it.  But glad I didn’t because I learned a lot and I made a cool thing!

I couldn’t find a function in Yoast that pulled post IDs or anything based on a primary category.  I needed to figure out how they assigned this.  I dug through the database and found a post meta with the key ‘_yoast_wpseo_primary_category.’  This is it, this is what I’ll use to build my end point.

The Code

First we need to register our endpoint/route.  I prefer building things in classes so I created a class:

<?php
class Rest_Api_Posts_By_Primary_Category {}

I register the endpoint in the __construct() as so:

https://gist.github.com/ChrisFlannagan/a6f63a02ea16268a25bc5d386e9ac63a#file-primary-cat-part-1-php

SITE_PREFIX is something I set in my theme’s functions.php file.  You need a namespace here so make it unique based on your plugin or theme or site in general.

The callback function is where the magic happens.  In get_posts_by_primary_cat( $data ) we do a simple WP_Query that makes use of the meta_query ability.  The thing is, I need the children of categories too.  Here’s an example similar to what I’m dealing with.

Let’s say we have three categories and these categories are what we see in our navigation menu: Math, Reading, History

Then those categories each have two children: ###-Lessons, ###-Research

So our final category structure looks like

Math
 – Math-Lessons
 – Math-Research
Reading
 – Reading-Lessons
 – Reading-Research
History
 – History-Lessons
 – History-Research

If someone clicks Reading I want to load all posts that have a primary category of Reading, Reading-Lessons or Reading-Research… so I need the children.

In the function below you can see I run get_categories on the selected category withe parent argument assigned.  This gets me all the children.  I just need their ids and I need them in string format so I run a quick foreach loop.   I make sure to add the original parent id back to the new array too.  Then I run the WP_Query.

https://gist.github.com/ChrisFlannagan/a6f63a02ea16268a25bc5d386e9ac63a#file-primary-cat-part-2-php

At this point you could just return $posts->posts but I needed the featured image and only a few of the pieces like title, time and a link.  So I built out what I need and return that.

Conclusion

Now to use this we simply visit http://yoursite.com/wp-json/SITE_PREFIX/v1/yoastprimary/##-catid-## and replace ##-catid-## with the actual category number.  I could’ve just made this a static class now that I think about it but whatever, you must remember to initiate it to work.  So in your functions.php of the theme or somewhere in your plugin call $rest_api_primary_cat = new Rest_Api_Posts_By_Primary_Category();

This was easy to parse in my javascript and is running great.  Hope it helps someone! Here’s the full code:

https://gist.github.com/ChrisFlannagan/a6f63a02ea16268a25bc5d386e9ac63a#file-primary-cat-php