WordPress Dropdown Select Menu of Custom Post Titles Associated with Custom Taxonomy Terms

Dropdown Custom Taxonomy PHP code and front-end example
Dropdown Custom Taxonomy PHP code and front-end example

Creating a dropdown select menu that lists only Custom Posts associated with the Custom Taxonomy Term “National Clients”

  • Custom Post Type: client (this is the slug)
  • Custom Taxonomy: client_status (this is the slug)
  • Custom Taxonomy Term: national-clients (this is the slug)
Custom Post Type, Custom Taxonomy, and Custom Taxonomy Term highlighted in WordPress editor
Custom Post Type, Custom Taxonomy, and Custom Taxonomy Term highlighted in WordPress editor

Front-end view of dropdown select menu for custom taxonomy term posts


// Query Arguments
$args = array(
	'posts_per_page'	=> '-1', // use -1 for all posts
	'orderby'			=> 'title',
	'order'				=> 'ASC',
	'post_type'			=> 'client', // the post type or custom post type
	'tax_query'			=> array( // Custom taxonomy query is an array of arrays
		array(
			'taxonomy'	=> 'client_status', // the custom taxonomy
			'field'		=> 'slug',                 
			'terms'		=> array('national-clients'), // term slug(s)
		),
	),
);
// The new Query
$the_query = new WP_Query( $args );
// The Loop		
if ( $the_query->have_posts() ) : // Start the if statement
?><!-- swap from PHP to HTML so select tag & onchange JS work properly -->
	<select onchange="window.document.location.href=this.options[this.selectedIndex].value;">
		<option selected="selected">NATIONAL CLIENTS</option><!-- Initial option in dropdown select menu; must be before the while loop -->
<?php // swap from HTML to PHP
			while ($the_query->have_posts()) : $the_query->the_post();
?><!-- swap from PHP to HTML -->
				<option value="<?php esc_url(the_permalink()); ?>"><?php esc_html(the_title()); ?></option><!-- The heart of the dropdown select menu. Displays custom post titles and their permalink URLs. -->
<?php // swap from HTML to PHP
			endwhile; // End the while Loop
?><!-- swap from PHP to HTML -->
	</select><!-- Close the select tag for the dropdown select menu -->
<?php // swap from HTML to PHP
endif; // End the if statement
wp_reset_postdata(); // reset global $post

A breakdown of the code

In order to create this dropdown select menu we need to craft custom Query arguments, a custom Query, and a custom Loop.

Symbols in PHP:

  • Dollar sign character (eg: $) indicates a variable
  • Equal sign (eg: =) is an assignment operator
  • Equal sign + greater than (eg: =>) is a double arrow operator (an assignment operator) between key/value pairs in an array
  • Single quotes (eg: ' ')
  • Commas (eg: ,)
  • Semi-colon (eg: ;) acts like the period at the end of a sentence
  • Backslashes (eg: //) are used for comments inside PHP

Part 1: Custom Query arguments

In order to reach into the WordPress database and query (retrieve) the specific custom posts that are only associated with a particular custom taxonomy term, we need to create a new WP_Query class. And the arguments for the new WP_Query class start with this bit of code below: an array of arguments assigned to a variable.

// Query Arguments
$args = array(
	'posts_per_page'	=> '-1',
	'orderby'			=> 'title',
	'order'				=> 'ASC',
	'post_type'			=> 'client',
	'tax_query'			=> array(
		array(
			'taxonomy'	=> 'client_status',
			'field'		=> 'slug',                 
			'terms'		=> array('national-clients'),
		),
	),
);
$args = array();

$args: A variable called $args will be assigned the Query arguments in the form of an array. The arguments in the array will tell the dropdown menu what to display. Written out: an array of arguments assigned to a variable called $args.

'posts_per_page' => '-1',

Posts per page: List all posts in the dropdown menu. This will override what your WordPress setup is set to display. In PHP, the double arrow operator (eg: =>) assigns the value to an array key. In this case, posts_per_page is the key and -1 is the value. The double arrow operator is specifically used because the argument is in an array.

'orderby' => 'title',

Orderby: We want to have the dropdown menu display the custom posts based on Title.

'order' => 'ASC',

Order: The order of the custom post titles in the dropdown menu can be descending (DESC: Z-A) or Ascending (ASC: A-Z).

'post_type' => 'client',

Post Type: The name of the Custom Post Type. In this case, client.

'tax_query' => array( array() ),

Taxonomy Query: tax_query is an array of an array, and will plug into the custom taxonomy and the custom taxonomy’s term.

Three parameters are specified in the tax_query‘s array of arrays: taxonomy, field, and terms. Read the WordPress Code Reference on Taxonomy Parameters for more details.

'taxonomy' => 'client_status',

Taxonomy: This is the name of the Custom Taxonomy that’s associated with the Custom Post Type. In this case the custom taxonomy is called Client Status. And the string for Client Status is client_status. Read the WordPress Code Reference on Taxonomy Parameters for more details.

'field' => 'slug',

Field: This is how the taxonomy term is selected in the database. In this case slug is the string assigned to the field parameter. Note that slug is one of several values accepted for the field parameter. Read the WordPress Code Reference on Taxonomy Parameters for more details.

'terms' => array('national-clients'),

Terms: This is the specific term created within the Custom Taxonomy that’s associated with the Custom Post Type. In this case National Clients is the name of the term, and the string for National Clients is national-clients. Note that array is one of the values accepted for the terms parameter. Read the WordPress Code Reference on Taxonomy Parameters for more details.

Part 2: Making the custom Query

Now that all of the custom Query arguments have been stuffed into the $args variable, it’s time to embed that $args variable into a custom Query.

// The new Query
$the_query = new WP_Query( $args );

$the_query: We’ll create a new Query by adding the keyword new in front of WP_Query (eg: new WP_Query). Then use the assignment operator (eg: =) to assign it to a variable called $the_query. Then add our $args variable (which was assigned Query arguments from earlier) as the parameter in the new WP_Query function. Parameters go inside the function’s parenthesis (eg: ( )).

Part 3: Making the custom Loop

Next up, customize the default WordPress Loop by adding our custom Query variable $the_query to the Loop. Read more about the WordPress Loop from WP Shout’s article Understanding The Loop: WordPress’s Way of Showing Posts and the WordPress Theme Handbook article The Loop.

// The Loop		
if ( $the_query->have_posts() ) : // Start the if statement
?><!-- swap from PHP to HTML so select tag & onchange JS work properly -->
	<select onchange="window.document.location.href=this.options[this.selectedIndex].value;">
		<option selected="selected">NATIONAL CLIENTS</option><!-- Initial option in dropdown select menu; must be before the while loop -->
<?php // swap from HTML to PHP
			while ($the_query->have_posts()) : $the_query->the_post();
?><!-- swap from PHP to HTML -->
				<option value="<?php esc_url(the_permalink()); ?>"><?php esc_html(the_title()); ?></option><!-- The heart of the dropdown select menu. Displays custom post titles and their permalink URLs. -->
<?php // swap from HTML to PHP
			endwhile; // End the while Loop
?><!-- swap from PHP to HTML -->
	</select><!-- Close the select tag for the dropdown select menu -->
<?php // swap from HTML to PHP
endif; // End the if statement
wp_reset_postdata(); // reset global $post
if ( $the_query->have_posts() ) :

if: Inside the if statement, we customize the have_posts() function by using the object operator (eg: ->) to connect our custom Query variable $the_query to the front of the have_posts() function.

What’s going on:

  • if statement (if the expression inside the function ( $the_query->have_posts() ) is true – if there are any posts to show – then run the code)
  • $the_query (the variable we created for our custom Query)
  • -> (the object operator connecting our custom Query variable $the_query to the have_posts() function)
  • have_posts() function (is actually a method that calls $wp_query->have_posts(). This is within The Loop object itself. We customize it by replacing the default $wp_query with our custom Query variable $the_query. See the 3rd paragraph under More Information in the WP_Query Code Reference.)
  • : at the end of the line (this is shorthand for the braces/curly brackets (eg: {}) that would normally encapsulate a block of code. Read more about what : means in PHP code.)
?><!-- swap from PHP to HTML so select tag & onchange JS work properly -->

?>: ?> is the PHP closing tag, so I can add HTML in the next line. I’m leaving the HTML comment in place because I’m still getting used to where PHP ends and HTML starts in the code.

HTML comments are written as: <!-- HTML comment here -->

<select onchange="window.document.location.href=this.options[this.selectedIndex].value;">

<select>: Select tag with inline onchange JavaScript. The select tag is what produces the dropdown menu.

The JavaScript (JS) is what makes the listings in the dropdown menu go to each custom post type page when an option in the dropdown is chosen. When there’s no onchange JS then the dropdown menu just displays each custom post type’s title, but doesn’t actually go to any URLs.

Source of the JavaScript: WP-Mix’s JavaScript redirect to URL on select. As WP-Mix points out: The bit of inline JavaScript loads the URL specified by whichever option the user selects. As soon the selection is made, the browser loads the URL.

WillMaster provides a good explanation of what the JavaScript code is doing.

What’s going on:

  • <select> tag produces the dropdown menu
  • onchange JavaScript takes control of the browser window and transforms the custom post type’s ID that was retrieved in our custom Query into a URL and takes the visitor directly to that page.
<option selected="selected">NATIONAL CLIENTS</option><!-- Initial option in dropdown select menu; must be before the while loop -->

<option>: Option tag with selected value; and HTML comment. This <option> is purposefully outside of the Loop (which starts further down) because we don’t want this value – NATIONAL CLIENTS – to be in the Loop. NATIONAL CLIENTS is not meant to do anything. It’s the same as “Choose one…” or “Pick one…” at the top of the dropdown menu. The selected="selected" part means the dropdown always starts with NATIONAL CLIENTS. Source for selected is from: Tutorial Republic’s How to populate dropdown list with array values in PHP

<?php // swap from HTML to PHP

<?php: <?php is the PHP opening tag, so I can swap from HTML back to PHP. I keep the PHP comment in place because I’m still getting used to where HTML ends and PHP starts in the code.

PHP comments are written as: // PHP comment

while ( $the_query->have_posts() ) : $the_query->the_post();

while: This is the beginning of the while loop. The while statement kicks off the while Loop in our custom Loop. As long as the while expression – what’s inside ( $the_query->have_posts() ) – is true, then our custom Loop will keep executing and display our custom post type page titles in the dropdown menu.

We’ve connected our custom Query variable $the_query to the have_posts() function using the object operator (eg: ->).

Notice the colon symbol (eg: :) in the middle of this line. It’s shorthand for the {} braces/curly brackets that would normally encapsulate a block of code.

Then we’ve connected our custom Query variable $the_query to the the_post() function using the object operator (eg: ->). Note the difference between $the_query->have_posts() and $the_query->the_post(): $the_query->have_posts vs $the_query->the_post.

The semi-colon (eg: ;) at the end of this line acts like the period at the end of a sentence, telling the PHP to stop.

?><!-- swap from PHP to HTML -->

?>: ?> is the PHP closing tag, so I can add HTML in the next line. In particular, we’ll be adding the <option> tag. I’m leaving the HTML comment in place because I’m still getting used to where PHP ends and HTML starts in the code.

This next line is the heart of the Dropdown Select Menu

<option value="<?php esc_url( the_permalink() ); ?>"><?php esc_html( the_title() ); ?></option>

<option>: The title of each custom post is displayed in the dropdown menu, and each title includes the URL to its custom post. This one line of code weaves in and out of HTML and PHP. To illustrate, HTML has a red background and PHP has a green background.

<option value="<?php esc_url( the_permalink() ); ?>"><?php esc_html( the_title() ); ?></option>

Here’s how this line of code is put together:

  1. Start with opening and closing HTML option tags with an empty value attribute, like so: <option value=""></option>
  2. Insert the PHP that displays each custom post’s URL between the quotation marks "" of the option value attribute, like so: <option value="<?php esc_url( the_permalink() ); ?>"></option>
  3. Insert the PHP that displays each custom post’s Title between the opening and closing HTML option tags, like so: <option value="<?php esc_url( the_permalink() ); ?>"><?php esc_html( the_title() ); ?></option>
  4. Note the semi-colons after the closing parenthesis symbol (eg: ); ); these terminate the PHP instructions

Details:

This dropdown select menu requires two properties: 1) the custom post’s Title; and 2) the custom post’s URL

  • In order to get the Title for each custom post the the_title() function is added between the <option> and </option> tags.
  • In order to get the URL for each custom post title the the_permalink() function is inserted as the option’s value attribute.

The Title and URL also need to be escaped. From the security section of the WordPress Theme Handbook: “Escaping is the process of securing output by stripping out unwanted data, like malformed HTML or script tags, preventing this data from being seen as code. Escaping helps secure your data prior to rendering it for the end user and prevents XSS (Cross-site scripting) attacks.”

  • The esc_url() helper function that surrounds the the_permalink() function checks and cleans the URL.
  • The esc_html() helper function that surrounds the the_title() function strips the text of invalid or special characters before output in HTML.
<?php // swap from HTML to PHP
endwhile; // End the while Loop
?><!-- swap from PHP to HTML -->
</select><!-- Close the select tag for the dropdown select menu -->
<?php // swap from HTML to PHP
endif; // End the if statement
wp_reset_postdata(); // reset global $post

Reset Postdata: When a custom Query like new WP_Query in Part 2 of this article has been created, it must be reset. From the WordPress Code Reference: “After looping through a separate query, this wp_reset_postdata() function restores the $post global to the current post in the main query.” Further info is available in the WordPress Theme Handbook’s Using wp_reset_postdata section.

Part 4: References

Leave a Comment

Your email address will not be published.

Scroll to Top