In the previous articles, we've known about what Custom Fields is and the application of custom fields which allows users to add arbitrary information into posts. But what do you do after that? In the recent post, you also learned how to add custom fields programmatically and display them in your theme. But you’ll see a shortcoming if there is no classification and searching. This post will guide you on how to get posts by custom fields in WordPress and we'll create an interesting application: advanced search.
If you have accessed some websites having the search function for hotel rooms or flights, you can see that the search function gives many different choices. That is called “advanced search”.
Unlike WordPress's default search function which allows users to search text based on the title and content only, advanced search allows you to search based on various criteria. In WordPress, we implement these criteria with the help of custom fields.
We will use the plugin in the previous post and modify directly the Twenty Seventeen theme.
Getting posts
Before learning how to get posts by custom fields, you have to know how to get posts. There are two ideal ways to get posts:
get_posts
: This function simply creates an instance ofWP_Query
then returns an array of post objects.- Using the class
WP_Query
: This way, you will have an instance ofWP_Query
and you can perform the query yourself. You can also have access to public methods and properties.
In this example, we'll use WP_Query
. To know the parameters of which constructor method WP_Query
accepts, please see here.
For example, the following snippet gets 2 random posts from the website:
$args = array( 'orderby' => 'rand', 'posts_per_page' => '2', ); $query = new WP_Query( $args );
Getting posts based on custom fields
WP_Query
accepts a parameter $meta_query
. This one will be used to create the instance of the WP_Meta_Query
class. Its purpose is to generate SQL code to query posts based on metadata.
This parameter is an array of meta conditions. Each condition is an array where you need to set the meta key, meta value, and the comparison. If the posts have meta values that satisfy the conditions, then they will be returned.
For example: To find posts that have the value of the hcf_price
field lower than 100, use the following code:
$args = array( 'meta_query' => array( array( 'key' => 'hcf_price', 'value' => '100', 'compare' => '<', 'type' => 'NUMERIC', ), ), ); $query = new WP_Query( $args );
WP_Meta_Query
WP_Meta_Query
is a helper that allows primary query classes, such as WP_Query
and WP_User_Query
to filter their results by object metadata, by generating JOIN and WHERE subclauses to be attached to the primary SQL query string.
Constructor method of class WP_Meta_Query
accepts the below parameters:
relation
: Optional. The MySQL keyword used to join the clauses of the query. Accepts 'AND', or 'OR'. Default 'AND'.- A no named array: Optional. An array of first-order clause parameters, or another fully-formed meta query.
key
: Meta key to filter by.value
: Meta value to filter by.compare
: MySQL operator used for comparing the value. Accepts '=', '!=', '>', '>=', '<', '<=', 'LIKE', 'NOT LIKE', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN', 'REGEXP', 'NOT REGEXP', 'RLIKE', 'EXISTS' or 'NOT EXISTS'. Default is 'IN' whenvalue
is an array, '=' otherwise.type
: MySQL data type that themeta_value
column will be CAST to for comparisons. Accepts 'NUMERIC', 'BINARY', 'CHAR', 'DATE', 'DATETIME', 'DECIMAL', 'SIGNED', 'TIME', or 'UNSIGNED'. Default is 'CHAR'.
Writing an advanced search
Firstly, you need to set up a plugin which we did in the previous post.
Now, we have 2 methods to implement advanced search:
- Hook into filter
pre_get_posts
to modify the parameters of the main query which WordPress uses to query the result of the search page. This method is encouraged. There is only one query and all plugins needing to change the list of posts will hook into it. So its compatibility is good. However, the result may not meet your desire because every plugin can hook into it and change the result. - Creating a page template and using a
WP_Query
to query posts and display them as the search result. This method is visual and easy to imagine how to useWP_Query
and custom field. Besides, you have the total right of controlling the query as well as the returns.
In this post, we choose the second method. This one helps us understand vividly the query and the way of interacting with custom fields when querying.
Create a page template
Create a file advanced-search.php
in the folder wp-content/themes/twentyseventeen/page-templates
with the below content:
<?php /** * Template Name: Advanced Search */
After that, go to Pages > Add New and add 1 new page with page template is Advanced Search as in the below picture:
Now, we display the search form in that page template. Edit the code of that page as follows:
<?php /** * Template Name: Advanced Search */ get_header(); ?> <div class="wrap"> <div id="primary" class="content-area"> <main id="main" class="site-main" role="main"> <form class="advanced-search-form"> <div class="form-group"> <label>Min Price</label> <input type="number" name="min-price"> </div> <div class="form-group"> <label>Max Price</label> <input type="number" name="max-price"> </div> <div class="form-group"> <input type="submit" value="Search"> </div> </form> </main><!-- #main --> </div><!-- #primary --> </div><!-- .wrap --> <?php get_footer();
Refresh the page and you will see that search form displayed as below:
Search by custom fields and display the result
Although the search form is available, you have not received the right result. And there's nothing that happens when you search with filled values of min price and max price. The reason is that we have not processed the query to take products that have the price in that range.
To get the values of min/max prices, use this code:
<?php $min_price = $_GET['min_price'] ?: ''; $max_price = $_GET['max_price'] ?: '';
Now, edit fields in the form as below:
Field min_price:
<input type="number" name="min_price" value="<?php echo esc_attr( $min_price ); ?>">
Field max_price:
<input type="number" name="max_price" value="<?php echo esc_attr( $max_price ); ?>">
Now, you need this code to display the search result:
<?php if ( $min_price || $max_price ): ?> <div class="search-result"> <?php $args = [ 'posts_per_page' => - 1, 'meta_query' => [] ]; if ( $min_price ) { $args['meta_query'][] = [ 'key' => 'hcf_price', 'value' => $min_price, 'compare' => '>=', 'type' => 'NUMERIC' ]; } if ( $max_price ) { $args['meta_query'][] = [ 'key' => 'hcf_price', 'value' => $max_price, 'compare' => '<=', 'type' => 'NUMERIC' ]; } $search_query = new WP_Query( $args ); if ( $search_query->have_posts() ): while ( $search_query->have_posts() ) { $search_query->the_post(); get_template_part( 'template-parts/post/content', 'excerpt' ); } wp_reset_postdata(); ?> <?php else: ?> <p>No result found.</p> <?php endif; ?> </div> <?php endif; ?>
Pay attention that there is a part of building parameters for the $args
query based on the value of min price and max price in the above code. We use a comparison function <=
, >=
to ensure that the price of products is in the selected pricing range.
The following screenshot is a result of clicking the Search button: displaying only products with prices from 1 to 300:
Besides, there is not only comparison conditions <=
, >=
but also many different ones such as =
, !=
and IN
. You can combine them with custom fields to build more complex queries. E.g finding products that have a green color, production year >= 2012, etc. See more about these conditions here.
You can download the full code of the file advanced-search.php
here.
Video tutorial
You can also watch the full video tutorial of this post here:
Conclusion
Each query by custom field will create a JOIN statement in SQL. So, if you have tens of custom fields, the performance of your code will decrease significantly. Therefore, if you see the query speed is too low, you optimize or cache that custom fields. Moreover, you should limit the number of custom fields queried.
Pay attention that custom fields are not created for querying. The main purpose of custom fields is to add data for the post. If your query so much, please consider using custom taxonomy instead.
We have learned how to create, display, and query posts based on the custom fields. Now, you have all the necessary knowledge to build anything interesting for your personal blog, please embark on doing this. If you have any questions, please comment below.
Another great post, as always! Thank you for all you do, and keep up the good work!
I have currently the Swiftype Search and Google Custom Search plugins installed to my site & blog. After reading your post, I wonder if I have to keep only one of them or it is okay to continue using both.
Thank you again!
https://redq.io/blog/wordpress-advanced-search-plugin