6

I currently have a custom post type named newcpt. This has 2 taxonomies, regionand city. In region i have regiona and regionb, and in city i have citya and cityb.

I currently am using the wp_dropdown_categories to get a drop-down of regiona. Is there a quick or easy solution to display a second dropdown which only displays if it also has regiona as a taxonomy.

So for example. I have a post of testpost which is in regiona and also in citya when regiona is selected from the drop-down i would like the second dropdown to populate cities with this region, so in this case citya

Once a city is also selected, it will grab all the posts from this cpt with the matching taxonomies on the same page. Any tips or helpful links are massively appreciated!!

  • You'r talking about front_end filter, like an widget or simliar, right? So I visit http://your.site and first see just your Region-Drop-Down. After I select an Region, I may also see the city-Dropdown, right? – lippoliv Aug 23 '16 at 07:36
  • Correct. So on a page of locations you would see a dropdown. Once the dropdown is selected with a choice the second dropdown appears with filtered options and the posts with this option filtered underneath. Once the third dropdown appears it filers the actual posts underneath –  Aug 23 '16 at 07:47
  • OK you can do that on server-side via PHP or on Client-Side via JavaScript. If you want to rely on php and wp_dropdown_categories it would be better to reload the page on each change of the drop-downs. So you can build the second Drop-Down server-sided with the information of the choosen region. You know what I mean? – lippoliv Aug 23 '16 at 08:21
  • Is there a way to make sure the page didnt reload, its important that the page loads and then the user will never see a refresh. Is there another way around this –  Aug 23 '16 at 08:23
  • Using less Javascript and some PHP you will generate a lot of HTML. That is no good Idea. I think best here will be to leave ``` wp_dropdown_categories ``` and generate JSON-Object via PHP with all the information and then use JavaScript / AngularJS to render the drop-downs in the browser. – lippoliv Aug 23 '16 at 08:32
  • How would I go about doing that? –  Aug 23 '16 at 08:36
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/121599/discussion-between-jdloader-and-lippoliv). –  Aug 23 '16 at 09:01
  • I think it is easy solution you can make a single taxonomy in this case you can easily filter and change dropdown dynamically using JavaScript ajax. In taxonomy first you make top of category all regions and his subcategory all cities like this Region A -> City 1, City 2, City 3 etc. Region A is root category and City 1, 2, 3 is child category of Region A. – user5200704 Aug 25 '16 at 12:28

3 Answers3

1

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)

lippoliv
  • 727
  • 2
  • 11
  • 28
  • 1
    This is a kind of ridiculous answer - he's asking for a WordPress-based solution. – serraosays Aug 23 '16 at 18:35
  • You can't legitimately ask this person to remove the entire theming layer of WordPress and replace it with WP-API and Angular. That's not a sensible solution. – serraosays Aug 24 '16 at 13:19
1

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 page
function 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 );
serraosays
  • 7,163
  • 3
  • 35
  • 60
  • Befor I would pay that 79$ I would use my JavaScript solution -.- May in an bigger usecase this Plugin could get really handy, but for that small task, I don't think it is worth it – lippoliv Aug 24 '16 at 05:10
  • I hear ya, but I'm billable at $125/hr - and this plugin solved about a day's worth of work for me, easily worth the cash but YMMV. – serraosays Aug 24 '16 at 13:10
1

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:

jQuery(document).ready(function($){
  "use strict";
  var parentSelectBox = $("#parent-select-box");

  parentSelectBox.change(function(e){

    e.preventDefault();

    var childForm = $("#child-select-box"), parentTermID = parentSelectBox.val();
    var terms = {
      "1": [
        {id: 11, name: "Child Term 1.1"},
        {id: 12, name: "Child Term 1.2"}
      ],
      "3": [
        {id: 21, name: "Child Term 2.1"},
        {id: 22, name: "Child Term 2.2"}
      ]
    };

    childForm.empty(); // Remove all old options.
    childForm.append('<option disabled selected>--Select a child term--</option>');

    if (terms.hasOwnProperty(parentTermID)) {
      var childTerms = terms[parentTermID];
      $.each(childTerms, function(){ // Add new options.
        childForm.append('<option value="' + this.id + '">' + this.name + '</option>');
      });
    } else {
      console.log('There are no child terms.');
    }
  });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form id="parent-from" class="form parent" method="post">
  <select id="parent-select-box" name="parent-term">
    <option disabled selected>--Select a parent term--</option>
    <option value="1">Parent Term 1</option>
    <option value="2">Parent Term 2</option>
  </select>
</form>
<form id="child-form" class="form child" method="get">
  <select id="child-select-box" name="child-term">
    <option disabled selected>--Select a child term--</option>
    <option value="3">Default Child Term 3</option>
    <option value="4">Default Child Term 4</option>
  </select>
</form>

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.

wpclevel
  • 2,451
  • 3
  • 14
  • 33