Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Filter wp_dropdown_categories by post type.
<?php
/**
* Using wp_dropdown_categories with the post type filter applied.
*
* @link https://joshuadnelson.com/category-taxonomy-dropdown-filtered-by-post-type/
*/
// Taxonomy dropdown arguments
$args = array(
'taxonomy' => 'department',
'post_type' => 'project', // filter by the post type 'project'
'echo' => true,
);
wp_dropdown_categories( $args );
<?php
/**
* Filter the term clauses using the arguments, specifically for the wp_dropdown_categories.
*
* @see http://wordpress.stackexchange.com/questions/207655/restrict-taxonomy-dropdown-to-post-type
* @see https://www.dfactory.eu/get_terms-post-type/
*
* @param array $clauses
* @param string $taxonomy
* @param array $args
*
* @return array
*/
add_filter( 'terms_clauses', 'jdn_post_type_terms_clauses', 10, 3 );
function jdn_post_type_terms_clauses( $clauses, $taxonomy, $args ) {
// Make sure we have a post_type argument to run with.
if( !isset( $args['post_type'] ) || empty( $args['post_type'] ) )
return $clauses;
global $wpdb;
// Setup the post types in an array
$post_types = array();
// If the argument is an array, check each one and cycle through the post types
if( is_array( $args['post_type'] ) ) {
// All possible, public post types
$possible_post_types = get_post_types( array( 'public' => true ) );
// Cycle through the post types, add them to our array if they are public
foreach( $args['post_type'] as $post_type ) {
if( in_array( $post_type, $possible_post_types ) )
$post_types[] = "'" . esc_attr( $post_type ) . "\'";
}
// If the post type argument is a string, not an array
} elseif( is_string( $args['post_type'] ) ) {
$post_types[] = "'" . esc_attr( $args['post_type'] ) . "'";
}
// If we have valid post types, build the new sql
if( !empty( $post_types ) ) {
$post_types_string = implode( ',', $post_types );
$fields = str_replace( 'tt.*', 'tt.term_taxonomy_id, tt.term_id, tt.taxonomy, tt.description, tt.parent', $clauses['fields'] );
$clauses['fields'] = 'DISTINCT ' . esc_sql( $fields ) . ', COUNT(t.term_id) AS count';
$clauses['join'] .= ' INNER JOIN ' . $wpdb->term_relationships . ' AS r ON r.term_taxonomy_id = tt.term_taxonomy_id INNER JOIN ' . $wpdb->posts . ' AS p ON p.ID = r.object_id';
$clauses['where'] .= ' AND p.post_type IN (' . $post_types_string . ')';
$clauses['orderby'] = 'GROUP BY t.term_id ' . $clauses['orderby'];
}
return $clauses;
}
<?php
/**
* A wrapper function for the custom dropdown, sets the current value by a url query var,
* adds a custom label, and a wrapper element.
*
* @author Joshua David Nelson, josh@joshuadnelson.com
*
* @link https://joshuadnelson.com/category-taxonomy-dropdown-filtered-by-post-type/
*
* @see https://codex.wordpress.org/Function_Reference/wp_dropdown_categories
*
* @param array $args
*
* @return string $output
*/
function jdn_get_custom_taxonomy_dropdown( $args ) {
// Taxonomy dropdown arguments
$defaults = array(
'taxonomy' => false, // required, the default here is a failsafe
'post_type' => false, // pass a value if you want to
'echo' => false, // true to echo, false for return
'label' => false, // false or pass a string for the label
'query_var' => false, // pass the query variable for the selected dropdown value
'id' => '', // set this and the default category 'name' argument
'wrap' => 'div', // the wrapper element. set to false to skip it.
'wrap_class' => 'select-wrap', // The custom wrapper class, set to false to skip it
);
$args = wp_parse_args( $args, $defaults );
// Be sure we're good to go.
if( ! $args['taxonomy'] )
return false;
// Current value of query variable, if there is one
if( $args['query_var'] ) {
$query_tax = get_query_var( esc_attr( $args['query_var'] ), false );
$current = $query_tax ? sanitize_text_field( $query_tax ) : '';
$args['selected'] = $current;
}
// We're returning the output of wp_dropdown_cateogies, but we need to know how the end user wants it back in this function,
// so we'll store that value as a variable and reset the echo argument for the wp_dropdown_categories.
$echo = esc_attr( $args['echo'] );
$args['echo'] = false;
// Grab the category dropdown
$tax_drop = wp_dropdown_categories( $args );
// Add a label
$label = ( $args['label'] && !empty( $args['id'] ) ) ? '<label for="' . esc_attr( $args['id'] ) . '">' . esc_attr( $args['label'] ) . '</label>' : '';
// Wrap it up
$class = $args['wrap_class'] ? ' class="' . esc_attr( $args['wrap_class'] ) . '"' : '';
$tax_drop = ( $args['wrap'] && !empty( $tax_drop ) ) ? '<' . esc_attr( $args['wrap'] ) . $class . '>' . $label . $tax_drop . '</' . esc_attr( $args['wrap'] ) . '>' : $tax_drop;
// Return it or echo it back
if( $echo ) {
echo $tax_drop;
} else {
return $tax_drop;
}
}
@19h47

This comment has been minimized.

Copy link

19h47 commented Jul 4, 2019

Very useful, thank you!

I had to query only post with post_status='publish' so I had to the $clauses['where'] this parameter

$clauses['where'] .= ' AND p.post_type IN (' . $post_types_string . ') AND p.post_status=\'publish\'';

Not sure if it’s the best solution but it works!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.