0

I've been googling and attempting this for over a week now with no success. I have a few custom post types (books, films, music etc), and a custom taxonomy (location).

On my frontpage, I have two dropdowns that filter a search, like this:

Look for: <custom post type> in <taxonomy>

What I am trying to do is have the second dropdown (location) filtered based on the first dropdown (cpt). So, if I choose "book", and there are only books in town X, and town Y, then only show town X and Y as options in the second dropdown. If anyone can help me get it right, you'll make my whole year! Below is my code for the two dropdowns (which are working, just not filtered):

<form action="<?php bloginfo('url'); ?>" method="get">

<?php 

$args = array(
'public'   => true,
'_builtin' => false
);

$output = 'objects'; // names or objects, note names is the default
$operator = 'and'; // 'and' or 'or'

$post_types = get_post_types($args, $output, $operator);

echo '<select class="selectboxSingle" name="post_type">';

foreach ( $post_types  as $post_type ) {

$exclude = array('custom_type');

if(TRUE === in_array($post_type->name,$exclude))
continue;

   echo '<option value="'.$post_type->slug.'">' . ucfirst($post_type->name) . '</option>';
}

echo "</select>";
?>

<div class="inx">in</div>

<?php 

// Set your custom taxonomy
$taxonomy = "location";

// Get all terms of the chosen taxonomy
$terms = get_terms($taxonomy, array('orderby' => 'name'));

// our content variable
$list_of_terms = '<select id="location" class="selectboxSingle" name="location">';

foreach($terms as $term){

    $select = ($current_selected = $term->slug) ? "selected" : "";

    if ($term->parent == 0 ) {

        // get children of current parent.
        $tchildren = get_term_children($term->term_id, $taxonomy);

    $children = array();
    foreach ($tchildren as $child) {
        $cterm = get_term_by( 'id', $child, $taxonomy );
        $children[$cterm->name] = $cterm;
    }
    ksort($children);

    // OPTGROUP FOR PARENTS
    if (count($children) > 0 ) {
             $list_of_terms .= '<optgroup label="'. $term->name .'">';
             if ($term->count > 0)
             $list_of_terms .= '<option value="'.$term->slug.'" '.$select.'>All '. $term->name .' </option>';
        } else
        $list_of_terms .= '<option value="'.$term->slug.'" '.$select.'>'. $term->name .' </option>';
    //$i++;

    // now the CHILDREN.
    foreach($children as $child) {
         $select = ($current_selected == $cterm->slug) ? "selected" : "";
         $list_of_terms .= '<option value="'.$child->slug.'" '.$select.'>'. $child->name.' </option>';

    } //end foreach

    if (count($children) > 0 ) {
        $list_of_terms .= "</optgroup>";
    }
}
}

$list_of_terms .= '</select>';

echo $list_of_terms; 
?>

</div>
<div class="submit-button-blanket"><button class="submit-button" type="submit">Search</button></div>
</form>
</div>
2
  • 1
    What is your exact problem? You can't construct the dropdown filter? You can't get the filtered results? Both?
    – cybmeta
    Aug 24 '14 at 13:24
  • Both:) I can't get the second dropdown options to filter based on the selection of the first dropdown. This is exactly what I'm trying to achieve: demo.rsjoomla.com/dynamic-drop-down-change-form-example
    – Guit4eva
    Aug 24 '14 at 19:49
2

If you want an example of how to do the dropdown filtering using ajax, then if you factor out your taxonomy dropdown into your "functions.php":

function my_dropdown_categories( $taxonomy, $current_selected = '', $include = null ) {
    // Get all terms of the chosen taxonomy
    $terms = get_terms($taxonomy, array('orderby' => 'name'));

    // our content variable
    $list_of_terms = '<select id="location" class="selectboxSingle" name="location">';

    if ( ! is_wp_error( $terms ) ) foreach($terms as $term){

        // If include array set, exclude unless in array.
        if ( is_array( $include ) && ! in_array( $term->slug, $include ) ) continue;

        $select = ($current_selected == $term->slug) ? "selected" : ""; // Note: ==

        if ($term->parent == 0 ) {

            // get children of current parent.
            $tchildren = get_term_children($term->term_id, $taxonomy);

            $children = array();
            foreach ($tchildren as $child) {
                $cterm = get_term_by( 'id', $child, $taxonomy );
                // If include array set, exclude unless in array.
                if ( is_array( $include ) && ! in_array( $cterm->slug, $include ) ) continue;
                $children[$cterm->name] = $cterm;
            }
            ksort($children);

            // OPTGROUP FOR PARENTS
            if (count($children) > 0 ) {
                 $list_of_terms .= '<optgroup label="'. $term->name .'">';
                 if ($term->count > 0)
                     $list_of_terms .= '<option value="'.$term->slug.'" '.$select.'>All '. $term->name .' </option>';
            } else
                $list_of_terms .= '<option value="'.$term->slug.'" '.$select.'>'. $term->name .' </option>';
            //$i++;

            // now the CHILDREN.
            foreach($children as $child) {
                 $select = ($current_selected == $child->slug) ? "selected" : ""; // Note: child, not cterm
                 $list_of_terms .= '<option value="'.$child->slug.'" '.$select.'>'. $child->name.' </option>';

            } //end foreach

            if (count($children) > 0 ) {
                $list_of_terms .= "</optgroup>";
            }
        }
    }

    $list_of_terms .= '</select>';

    return $list_of_terms;
}

And also in your "functions.php", you put in the ajax handling:

add_action( 'wp_ajax_wpse158929_get_terms_for_cpt', 'wpse158929_get_terms_for_cpt' );
add_action( 'wp_ajax_nopriv_wpse158929_get_terms_for_cpt', 'wpse158929_get_terms_for_cpt' );

function wpse158929_get_terms_for_cpt() {
    $ret = array( 'html' => '', 'error' => false );

    if ( ! check_ajax_referer( 'wpse158929_get_terms_for_cpt_submit_', 'nonce', false /*die*/ ) ) {
        $ret['error'] = __( 'Permission error', 'wpfm' );
    } else {
        $post_type = isset( $_REQUEST['post_type'] ) ? $_REQUEST['post_type'] : '';
        $taxonomy = isset( $_REQUEST['taxonomy'] ) ? $_REQUEST['taxonomy'] : '';
        $current_selected = isset( $_REQUEST['current_selected'] ) ? $_REQUEST['current_selected'] : '';

        if ( ! $post_type || ! $taxonomy ) {
            $ret['error'] = __( 'Params error', 'wpfm' );
        } else {
            global $wpdb;
            $sql = $wpdb->prepare( 'SELECT t.slug FROM ' . $wpdb->terms . ' t'
                . ' JOIN ' . $wpdb->term_taxonomy . ' AS tt ON tt.term_id = t.term_id'
                . ' JOIN ' . $wpdb->term_relationships . ' AS tr ON tr.term_taxonomy_id = tt.term_taxonomy_id'
                . ' JOIN ' . $wpdb->posts . ' AS p ON p.ID = tr.object_id'
                . ' WHERE tt.taxonomy = %s AND p.post_type = %s AND p.post_status = %s'
                . ' GROUP BY t.slug'
                , $taxonomy, $post_type, 'publish' );
            $include = $wpdb->get_col($sql);
            $ret['html'] = preg_replace( '/<\/?select[^>]*>/', '', my_dropdown_categories( $taxonomy, $current_selected, $include ) );
        }
    }

    wp_send_json( $ret );
}

Then append the jquery to your main code:

<form action="<?php bloginfo('url'); ?>" method="get">

<?php 

$args = array(
'public'   => true,
'_builtin' => false
);

$output = 'objects'; // names or objects, note names is the default
$operator = 'and'; // 'and' or 'or'

$post_types = get_post_types($args, $output, $operator);

echo '<select class="selectboxSingle" name="post_type">';

foreach ( $post_types  as $post_type ) {

$exclude = array('custom_type');

if(TRUE === in_array($post_type->name,$exclude))
continue;

   // Note: I think you need to use query_var here, rather than slug.
   echo '<option value="'.$post_type->query_var.'">' . ucfirst($post_type->name) . '</option>';
}

echo "</select>";
?>

<div class="inx">in</div>

<?php 

// Set your custom taxonomy
$taxonomy = "location";

// Factored out taxonomy dropdown into function my_dropdown_categories() in "functions.php".
echo my_dropdown_categories( $taxonomy );
?>

</div>
<div class="submit-button-blanket"><button class="submit-button" type="submit">Search</button></div>
</form>
</div>
<script type="text/javascript">
jQuery(document).ready(function() {
    (function ($) {
        $('select[name="post_type"]').change(function (event) {
            $.post( <?php echo json_encode( admin_url( 'admin-ajax.php' ) ); ?>, {
                    action: 'wpse158929_get_terms_for_cpt',
                    post_type: $(this).val(),
                    taxonomy: <?php echo json_encode( $taxonomy ); ?>,
                    current_selected: $('select[name="location"]').val(),
                    nonce: <?php echo json_encode( wp_create_nonce( 'wpse158929_get_terms_for_cpt_submit_' ) ); ?>
                }, function( response ) {
                    if ( response && !response.error ) {
                        $('select[name="location"]').html(response.html);
                    }
                }, 'json'
            );
        });
        // Remove if you don't want to call change immediately.
        $('select[name="post_type"]').change();
    })(jQuery);
});
</script>

you'll get some way to what you want.

7
  • I almost fell off my chair!!!!!! You are an absolute GURU!!! Thanks soooooo much!!!!!!!!!!! :D :D :D
    – Guit4eva
    Aug 25 '14 at 8:47
  • Hey again:) Your code is working really well, just wanted to ask you a quick question though, is there anyway to get it to work in >IE8?
    – Guit4eva
    Aug 28 '14 at 17:38
  • The problem may be that the <select> tag is being returned to the ajax function - try stripping it out on the $ret['html'] assignment eg preg_replace( '/<\/?select[^>]*>/', '', my_dropdown_categories( ... - I'll edit the answer...
    – bonger
    Aug 28 '14 at 19:16
  • Guit4eva, this was an amazing answer from bonger. Have some courtesy and give the fella some rep! Aug 28 '14 at 19:25
  • Amazing is putting it lightly!:D I've seriously been at it for around...10 hours now, no jokes. And here bonger comes and fixes it immediately, working flawlessly as far back as IE6! Oh man, thank you so, so, SOOO much, you are my freaken hero!!! :D
    – Guit4eva
    Aug 28 '14 at 19:32
0

Use jQuery action on first dropdown .. this is the code from your mentioned url .. You can populate the arrays using php functions ...

function dynamic1(parent,child)
{
    var parent_array = new Array();
    // This is the default value
    parent_array[''] = ['Please select a manufacturer'];
    // All other elements
    // parent_array['PARENT NAME'] = ['CHILD 1','CHILD 2','CHILD 3','ETC'];
    parent_array['Audi'] = ['A3','A4','A5','A6','A8','Q5','Q7','S3','S4','S5','S6','S8','RS6'];
    parent_array['Dacia'] = ['Sandero','Logan'];
    parent_array['FIAT'] = ['Bravo','Punto','Grande Punto'];
    parent_array['Peugeot'] = ['207','308','407','607'];
    parent_array['SEAT'] = ['Ibiza','New Ibiza','Leon'];
    parent_array['Skoda'] = ['Fabia','Octavia Tour','Octavia 2','Superb'];

    // Get the child
    var thechild = document.getElementById(child);

    // Remove all other options from the select element
    thechild.options.length = 0;

    // What value are we looking for ?
    var parent_value = parent.options[parent.selectedIndex].value;

    // No value found, use the default value
    if (!parent_array[parent_value]) parent_value = '';

    // Set the correct length
    thechild.options.length = parent_array[parent_value].length;

    // Add the options
    for(var i=0;i<parent_array[parent_value].length;i++)
    {
        thechild.options[i].text = parent_array[parent_value][i];
        thechild.options[i].value = parent_array[parent_value][i];
    }
}
1
  • I'm going to mark bongers answer as the right one, since it worked flawlessly right away, but thanks for trying to help:)
    – Guit4eva
    Aug 25 '14 at 8:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.