Wordpress Filter multiple drop-down taxonomies to display custom field via ajax
I think the best solution is to use PHP to generate the data-set and use for example AngularJS to show on client site.
JavaScript
angular.module('app', []).controller('controller', [ '$scope', '$attrs', function ($scope, $attrs) { $scope.data=JSON.parse($attrs.selects); $scope.region = {}; $scope.city = {}; $scope.loadCitys = function () { $scope.region = JSON.parse($scope.region); }; $scope.loadPosts = function () { $scope.city = JSON.parse($scope.city); }; }]);
And HTML
<!DOCTYPE html><html ng-app="app"> <head> <script src="https://code.angularjs.org/1.5.8/angular.js"></script> <link rel="stylesheet" href="style.css" /> </head> <body ng-controller="controller" data-selects='[{"name":"Region 1","citys":[{"name":"City 1","posts":[{"title":"Post 1","id":1},{"title":"Post 2","id":2}]}]},{"name":"Region 2","citys":[{"name":"City 2","posts":[{"title":"Post 3","id":3},{"title":"Post 4","id":4}]},{"name":"City 3","posts":[{"title":"Post 5","id":5},{"title":"Post 6","id":6}]}]}]'> <div> Region: {{region.name}} <br> City: {{city.name}} </div> <select ng-model="region" ng-change="loadCitys()"> <option ng-repeat="tregion in data" value="{{tregion}}">{{tregion.name}}</option> </select> <select ng-model="city" ng-change="loadPosts()"> <option ng-repeat="tcity in region.citys" value="{{tcity}}">{{tcity.name}}</option> </select> <select ng-model="post"> <option ng-repeat="tpost in city.posts" value="{{tpost}}">{{tpost.title}}</option> </select> <script src="script.js"></script> </body></html>
Living example: https://plnkr.co/edit/gyzCxMpn9luAcGsLZHYD
(You have to finalize it)
FacetWP does what you want but might even be better than what you've laid out - AJAX updates to a data set based on taxonomy filters. You'd have both dropdowns showing regions and cities, users could toggle what they need. If you wanted to do the dependent dropdown concept, you can make a custom facet.
Usage is straightforward - here is how to use it with WP_query:
<?php // 1- Setup WP_query variable to get all your content // Logic here is descending alphabetical of all content // FacetWP handles granular search winnowing // Note the facetwp array item $args = array( 'posts_per_page' => 9999, 'post_type' => array('new-cpt', 'work-featured'), 'orderby' => 'rand', 'facetwp' => true, // so we can hook into facetwp via functions.php ); $the_query = new WP_Query( $args ); // 2- Setup new loop if($the_query->have_posts()) { while($the_query->have_posts()) : $the_query->the_post(); // do your thing endwhile; } wp_reset_postdata();?>
Once you setup the taxonomies in wp-admin
, you can output the taxonomy filters right into your code (maybe a sidebar or wherever you need it):
<?php echo facetwp_display( 'facet', 'region' ); ?><?php echo facetwp_display( 'facet', 'cities' ); ?>
Another note - since you are using custom post-types, you will have to add a custom filter to your functions.php file:
// Adding in custom filter for FacetWP to detect custom WP_Query on facet pagefunction my_facetwp_is_main_query( $is_main_query, $query ) { if ( isset( $query->query_vars['facetwp'] ) ) { $is_main_query = true; } return $is_main_query;}add_filter( 'facetwp_is_main_query', 'my_facetwp_is_main_query', 10, 2 );
It's hard to figure out your real world problem but I will try my best:
Let me visualize what you're trying to archive:
As you can see, after you selected the Parent Term 1
in the first select box, in the second select box, the child terms (Child Term 1.1
and Child Term 1.2
) are populated automatically. If you have selected the Parent Term 2
, you will see There are no child terms.
on the console.
But it's plain HTML/JS, we have to incorporate it into WordPress:
First of all, I suppose that you know how to use AJAX to retrieve data in WordPress.
The first select box is a filter to retrieve data for the second select box. We will use AJAX base on .change()
event of the parent select box:
jQuery(document).ready(function($){ "use strict"; var parentSelectBox = $("#parent-select-box"); parentSelectBox.change(function(e){ // .change() e.preventDefault(); var parentTermID = parentSelectBox.val(); // { // Some code with AJAX to get child terms base on `parentTermID` here. // } // Now, suppose `terms` is AJAX response. if ($.isEmptyObject(terms)) { // There're no child terms. // Do something... } else { // Append them to the second select box. } });});
For the second select box, I don't know about DOM structure of your document but I think we don't need AJAX. Use GET
method with .change()
event:
jQuery(document).ready(function($){ "use strict"; var childForm = $("#child-form"), childSelectBox = $("#child-select-box"); childSelectBox.change(function(e){ e.preventDefault(); childForm.submit(); });});
Now, right after user select a child term, child form will be submit automatically and append child-term
to the URL via GET
method. We will use this value with pre_get_posts
action to filter posts result:
add_action('pre_get_posts', function(\WP_Query $query) { // If you're using main query, remember to check `$query->is_main_query()` as well. if ( isset($_GET['child-term']) && !empty($_GET['child-term']) ) { $query->query_vars['tax_query'] = [ [ 'field' => 'term_id', 'terms' => absint($_GET['child-term']), 'taxonomy' => 'city' ] ]; }});
You may need to see taxonomy parameters for more info.