Wordpress: pre_get_posts and order by taxonomy term - wordpress

I have a category archive with a custom taxonomy "client". Now I want to order the category archive by the term of the custom taxonomy (the client name). I tried to query it by meta_value and a advanced custom taxonomy query, but I could not get it to be ordered by the name of the taxonomy term. Any suggestions to get a Wordpress loop ordered by taxonomy term name? See line $query->set( 'orderby', 'how_to_order_by_taxonomy_name' );
Registering the taxonomy
add_action( 'init', 'jp_register_project_taxonomies', 0 );
function jp_register_project_taxonomies() {
// register taxonomy to hold our clients
register_taxonomy(
'client',
array( 'post' ),
array(
'hierarchical' => false,
'public' => true,
'query_var' => true,
'rewrite' => true,
'labels' => array(
'name' => _x( 'Clients', 'taxonomy general name' ),
'singular_name' => _x( 'Client', 'taxonomy singular name' ),
'search_items' => __( 'Search Clients' ),
'all_items' => __( 'All Clients' ),
'edit_item' => __( 'Edit Client' ),
'update_item' => __( 'Update Client' ),
'add_new_item' => __( 'Add New Client' ),
'new_item_name' => __( 'New Client Name' ),
'menu_name' => __( 'Client' )
),
)
);
}
pre_get_posts Query
add_action( 'pre_get_posts', 'jp_project_taxonomy_queries' );
function jp_project_taxonomy_queries( $query ) {
if(!is_admin() && $query->is_main_query() && is_category() ):
if (get_query_var('poby') == 'client'):
$taxonomies = array();
$tax_order = (get_query_var('po') == 'DESC' ? 'DESC' : 'ASC' );
foreach (get_terms('client', array('order' => $tax_order)) as $tax ) {
$taxonomies[] = $tax->name;
}
$taxquery = array(
array(
'taxonomy' => 'client',
'terms' => $taxonomies,
'field' => 'slug',
)
);
$query->set( 'tax_query', $taxquery );
$query->set( 'orderby', 'how_to_order_by_taxonomy_name' );
endif;
endif;
}

As far as I know, there is no parameter to order a WP_Query by term.
My solution to this problem usually is to create a meta field that contains the term name or the term slug. This field is created when the post is saved using the hook save_post or save_post_{post_type}.
For instance, to order a list of books (post type book) by year of publication (taxonomy date) we can use this function to create the meta field:
add_action( 'save_post_book', 'prefix_save_date_as_meta', 10 );
function prefix_save_date_as_meta ($post_id) {
$years = get_the_terms($post_id,'date');
if( empty($years) )
return;
$years_list = wp_list_pluck($years,'name');
update_post_meta($post_id,'_book_date',$years_list[0]);
return;
}
And this other function to order the query:
add_filter( 'pre_get_posts', 'prefix_custom_args_for_loops' );
function prefix_custom_args_for_loops( $query ) {
if ( !is_admin() && is_post_type_archive('book') && $query->is_main_query() ) {
$query->set( 'orderby','meta_value_num');
$query->set( 'meta_key','_book_date');
}
return $query;
}

Related

Custom post type taxonomy not being replaced in ACF post object field output

I have a custom post type (Photos) and a taxonomy (Locations) setup on my client's website. The permalinks work correctly when accessed using the menus, search, and directly from the custom post type in the WordPress admin panel, but not when accessing them using an Advanced Custom Fields post object field in my Timber/Twig template. The taxonomy portion (%locations%) of the URL is not being replaced. For example, http://example.com/photos/`%locations%`/taj-mahal-and-the-ganges/. The %locations% should be replaced with world and india, which are locations from the custom taxonomy.
The post's custom post object field is being pulled into the template using the following code: {{ __('View photo gallery', textdomain) }}.
I have included my custom post type and taxonomy code below:
function textdomain_register_photos_post_type() {
$args = [
'label' => 'Photo Galleries',
'labels' => [
'singular_name' => _x( 'Photo Gallery', 'singular' ),
'menu_name' => _x( 'Photo Galleries', 'admin menu' ),
'name_admin_bar' => _x( 'Photo Galleries', 'admin bar' ),
'add_new' => _x( 'Add New', 'add new' ),
'add_new_item' => __( 'Add New Photo Gallery' ),
'new_item' => __( 'New Photo Gallery' ),
'edit_item' => __( 'Edit Photo Gallery' ),
'view_item' => __( 'View Photo Gallery' ),
'all_items' => __( 'All Photo Galleries' ),
'search_items' => __( 'Search Photo Galleries' ),
'not_found' => __( 'No photo galleries found.' ),
],
'supports' => array(
'title',
'editor',
'thumbnail'
),
'public' => true,
'menu_position' => 5,
'menu_icon' => 'dashicons-format-gallery',
'capability_type' => 'post',
'taxonomies' => [ 'locations', ],
'has_archive' => true,
'delete_with_user' => false,
'rewrite' => [
'slug' => 'photos/%locations%',
'with_front' => false,
],
];
register_post_type( 'photos', $args );
};
add_action( 'init', 'textdomain_register_photos_post_type' );
function textdomain_register_locations_taxonomy() {
$args = [
'labels' => [
'name' => _x( 'Locations', 'taxonomy general name' ),
'singular_name' => _x( 'Location', 'taxonomy singular name' ),
'search_items' => __( 'Search Locations' ),
'all_items' => __( 'All Locations' ),
'parent_item' => __( 'Parent Location' ),
'parent_item_colon' => __( 'Parent Location:' ),
'edit_item' => __( 'Edit Location' ),
'update_item' => __( 'Update Location' ),
'add_new_item' => __( 'Add New Location' ),
'new_item_name' => __( 'New Location Name' ),
'menu_name' => __( 'Locations' ),
],
'hierarchical' => true,
'rewrite' => [
'slug' => 'locations',
'hierarchical' => true,
],
];
register_taxonomy( 'locations', [ 'photos' ], $args );
};
add_action( 'init', 'textdomain_register_locations_taxonomy' );
add_filter( 'post_type_link', 'textdomain_post_type_link', 10, 2 );
function textdomain_post_type_link( $post_link, $post ) {
// Bail out if not photos post type.
if ( 'photos' !== $post->post_type ) {
return $post_link;
}
$taxonomy = 'locations';
$terms = get_the_terms( get_the_ID(), $taxonomy );
$slug = [];
foreach ( $terms as $term ) {
if ( $term->parent == 0 ) {
array_unshift( $slug, sanitize_title_with_dashes( $term->name ) );
} else {
array_push( $slug, sanitize_title_with_dashes( $term->name ) );
}
}
if ( ! empty( $slug ) ) {
$post_link = str_replace( '%' . $taxonomy . '%', join( '/', $slug ), $post_link );
}
return $post_link;
}
I have saved my permalinks multiple times and have flush_rewrite_rules(); at the bottom of my theme's functions file.
Update
WordPress is displaying this warning Invalid argument supplied foreach() on line 422 of the functions.php file. The code is as follows:
$taxonomy = 'locations';
$terms = get_the_terms( get_the_ID(), $taxonomy );
$slug = [];
foreach ( $terms as $term ) {
if ( $term->parent == 0 ) {
array_unshift( $slug, sanitize_title_with_dashes( $term->name ) );
} else {
array_push( $slug, sanitize_title_with_dashes( $term->name ) );
}
}
I am not sure if this could be causing the issue, but my PHP knowledge is limited.
Any tips or suggestions on this issue are greatly appreciated.
I figured out the issue was related to how the post ID was being retrieved for the taxonomies. I reviewed the get_the_terms function reference and found that get_the_ID() needed to be replaced by $post->ID in the following line: $terms = get_the_terms( $post->ID, $taxonomy );. My updated and working function is below.
add_filter( 'post_type_link', 'textdomain_post_type_link', 10, 2 );
function textdomain_post_type_link( $post_link, $post ) {
// Bail out if not photos post type.
if ( 'photos' !== $post->post_type ) {
return $post_link;
}
$taxonomy = 'locations';
// Replaced get_the_ID() with $post->ID
$terms = get_the_terms( $post->ID, $taxonomy );
$slug = [];
foreach ( $terms as $term ) {
if ( $term->parent == 0 ) {
array_unshift( $slug, sanitize_title_with_dashes( $term->name ) );
} else {
array_push( $slug, sanitize_title_with_dashes( $term->name ) );
}
}
if ( ! empty( $slug ) ) {
$post_link = str_replace( '%' . $taxonomy . '%', join( '/', $slug ), $post_link );
}
return $post_link;
}

Add custom taxonomy term in woocommerce REST API

I have created custom taxonomy "Brands" and attached to woocommerce products. Unfortunately, It is not available in woocommerce REST API response.
How to attach custom taxonomy term to woocommerce rest API. Currently there is no documentation about attachment of custom taxonomy. Is there any hook or filter ?
I solved by using this code.You will be able to GET and Update custom taxonomy by using this method. Basically. You can add this code in functions.php file or in plugin.
Step:1
Replace brands with your taxonomy_name.
Step:2
If your taxonomy have custom fields, replace custom_field_name with yours.
Taxonomy Code:
add_action( 'init', 'create_brands_hierarchical_taxonomy', 0 );
//create a custom taxonomy name it topics for your posts
function create_brands_hierarchical_taxonomy() {
// Add new taxonomy, make it hierarchical like categories
//first do the translations part for GUI
$labels = array(
'name' => _x( 'Brands', 'taxonomy general name' ),
'singular_name' => _x( 'Brand', 'taxonomy singular name' ),
'search_items' => __( 'Search Brands' ),
'all_items' => __( 'All Brands' ),
'parent_item' => __( 'Parent Brand' ),
'parent_item_colon' => __( 'Parent Brand:' ),
'edit_item' => __( 'Edit Brand' ),
'update_item' => __( 'Update Brand' ),
'add_new_item' => __( 'Add New Brand' ),
'new_item_name' => __( 'New Brand Name' ),
'menu_name' => __( 'Brands' ),
);
$capabilities = array(
'manage_terms' => 'manage_woocommerce',
'edit_terms' => 'manage_woocommerce',
'delete_terms' => 'manage_woocommerce',
'assign_terms' => 'manage_woocommerce',
);
// Now register the taxonomy
$args = array(
'labels' => $labels,
'show_in_rest' => true,
'hierarchical' => true,
'public' => true,
'show_ui' => true,
'show_admin_column' => false,
'show_in_nav_menus' => true,
'show_tagcloud' => true,
'capabilities' => $capabilities,
);
register_taxonomy( 'brands', array( 'product' ), $args );
register_taxonomy_for_object_type( 'brands', 'product' );
}
Register Taxonomy API for WC
//Register taxonomy API for WC
add_action( 'rest_api_init', 'register_rest_field_for_custom_taxonomy_brands' );
function register_rest_field_for_custom_taxonomy_brands() {
register_rest_field('product', "brands", array(
'get_callback' => 'product_get_callback',
'update_callback' => 'product_update_callback',
'schema' => null,
));
}
//Get Taxonomy record in wc REST API
function product_get_callback($post, $attr, $request, $object_type)
{
$terms = array();
// Get terms
foreach (wp_get_post_terms( $post[ 'id' ],'brands') as $term) {
$terms[] = array(
'id' => $term->term_id,
'name' => $term->name,
'slug' => $term->slug,
'custom_field_name' => get_term_meta($term->term_id, 'custom_field_name', true)
);
}
return $terms;
}
//Update Taxonomy record in wc REST API
function product_update_callback($values, $post, $attr, $request, $object_type)
{
// Post ID
$postId = $post->get_id();
//Example: $values = [2,4,3];
// Set terms
wp_set_object_terms( $postId, $values , 'brands');
}
Solution above is working but you have to change the
$postId = $post->get_id();
with
$postId = $post->ID;
Took me ages to find out why update_callback did not work : $values contains the taxonomy-structure and is therefore too complex to pass as integer to wp_set_object_terms. You have to strip it to the numeric ID's only otherwise [null] is assigned
//Update Taxonomy record in wc REST API
function product_update_callback_Leerjaar($values, $post, $attr, $request, $object_type)
{
// Post ID
$postId = $post->id;
//Example: $values = [2,4,3];
error_log("debug on values");
error_log(json_encode($values));
$numarray = [];
foreach($values as $value){
$numarray[] = (int)$value['id'];
}
wp_set_object_terms( $postId, $numarray , 'brands');
}
If anyone has tested all the above and can't get it to work, I found a simplest and working solution, based on Taha Farooqui's answer and the wordpress register_rest_field documentation :
add_action( 'rest_api_init', 'register_rest_field_for_custom_taxonomy_brands');
function register_rest_field_for_custom_taxonomy_brands() {
register_rest_field('product', "field_rest_name",
array("get_callback" => function ($post) {
$taxonomy = wp_get_post_terms( $post['id'], 'your_taxonomy_name');
return $taxonomy;
}
)
);
}
After months of testing trying to prove why the product_update_callback() function returned a null value, he got a version that loads the taxonomy values ​​from the woocommerce Rest Api v3 only with the name and slug..
<?php
//Prevent a malicious user from executing php code from the browser bar
defined('ABSPATH') or die( "Bye bye" );
add_action( 'init', 'create_brands_hierarchical_taxonomy', 0 );
//create a custom taxonomy name it topics for your posts
function create_brands_hierarchical_taxonomy() {
// Add new taxonomy, make it hierarchical like categories
$labels = array(
'name' => _x( 'Marcas', 'taxonomy general name' ),
'singular_name' => _x( 'Marca', 'taxonomy singular name' ),
'search_items' => __( 'Buscar Marcas' ),
'all_items' => __( 'Todas las Marcas' ),
'parent_item' => __( 'Marca Relacionada' ),
'parent_item_colon' => __( 'Marca Relacionada:' ),
'edit_item' => __( 'Editar Marca' ),
'update_item' => __( 'Subir Marca' ),
'add_new_item' => __( 'Añadir Nueva Marca' ),
'new_item_name' => __( 'Nuevo Nombre de Marca' ),
'menu_name' => __( 'Marcas' ),
);
$capabilities = array(
'manage_terms' => 'manage_woocommerce',
'edit_terms' => 'manage_woocommerce',
'delete_terms' => 'manage_woocommerce',
'assign_terms' => 'manage_woocommerce',
);
// Now register the taxonomy
$args = array(
'labels' => $labels,
'show_in_rest' => true,
'hierarchical' => true,
'public' => true,
'show_ui' => true,
'show_admin_column' => false,
'show_in_nav_menus' => true,
'show_tagcloud' => true,
'capabilities' => $capabilities,
);
register_taxonomy( 'pwb-brand', array( 'product' ), $args );
register_taxonomy_for_object_type( 'pwb-brand', 'product' );
}
//Register taxonomy API for WC
add_action( 'rest_api_init', 'register_rest_field_for_custom_taxonomy_brands' );
function register_rest_field_for_custom_taxonomy_brands() {
register_rest_field('product', "pwb-brand", array(
'get_callback' => 'product_get_callback_brand',
'update_callback' => 'product_update_callback_brand',
'schema' => null,
));
}
//Get Taxonomy record in wc REST API
function product_get_callback_brand($post, $attr, $request, $object_type){
$terms = array();
// Get terms
foreach (wp_get_post_terms( $post[ 'id' ],'pwb-brand') as $term) {
$terms[] = array(
'id' => $term->term_id,
'name' => $term->name,
'slug' => $term->slug,
);
}
return $terms;
}
//Update Taxonomy record in wc REST API
function product_update_callback_brand($values, $post, $attr, $request, $object_type){
// Post ID
$postId = $post->id;
$terms = $values;
$termName = $terms[0]['name'];
$termSlug = $terms[0]['slug'];
wp_insert_term( $termName, 'pwb-brand', array( 'slug' => $termSlug ) );
error_log("debug on values");
error_log(json_encode($values));
$newTermId = get_term_by('slug',$termSlug,'pwb-brand')->term_id;
array_push($values, array('id' => (int)$newTermId));
$numarray = [];
foreach($values as $value){
if(is_numeric($value['id'])){
$numarray[] = (int)$value['id'];
}
}
wp_set_object_terms( $postId, $numarray , 'pwb-brand');
}
After so much testing he understood that the values ​​that pass through the product_get_callback_brand function are mandatory to register a taxonomy so if you add a custom field like in the first example then they must be loaded so that the taxonomy can be retrieved.
It is worth noting that it is not a valid field for image fields or galleries that will not have the permissions to be loaded by the Rest Api v3 of woocommerce

How To Modify Show UI of a Registered Taxonomy On Demand

As you you know the 'show_ui' Boolean option in taking care of rendering or not rending the Taxonomy Menu on UI on registering ataxonomy.
function custom_taxonomy() {
$labels = array(
'name' => 'Taxonomies',
'singular_name' => 'Taxonomy',
'menu_name' => 'Taxonomy',
'all_items' => 'All Items',
'parent_item' => 'Parent Item',
'parent_item_colon' => 'Parent Item:',
'new_item_name' => 'New Item Name',
'add_new_item' => 'Add New Item',
'edit_item' => 'Edit Item',
'update_item' => 'Update Item',
'view_item' => 'View Item',
'separate_items_with_commas' => 'Separate items with commas',
'add_or_remove_items' => 'Add or remove items',
'choose_from_most_used' => 'Choose from the most used',
'popular_items' => 'Popular Items',
'search_items' => 'Search Items',
'not_found' => 'Not Found',
'no_terms' => 'No items',
'items_list' => 'Items list',
'items_list_navigation' => 'Items list navigation',
);
$args = array(
'labels' => $labels,
'hierarchical' => false,
'public' => true,
'show_ui' => true,
'show_admin_column' => true,
'show_in_nav_menus' => true,
'show_tagcloud' => true,
);
register_taxonomy( 'taxonomy', array( 'post' ), $args );
}
add_action( 'init', 'custom_taxonomy', 0 );
Is there any way to modify this option after registering the taxonomy? like any hook or filter to toggle the Boolean in functions.php
You can use register_taxonomy_args to filter the taxonomy options before the taxonomy is registered, or while it's being registered.
Example code:
/*
* #param array $args The taxonomy args such as show_ui.
* #param string $taxonomy The taxonomy name.
*/
add_filter( 'register_taxonomy_args', function ( $args, $taxonomy ) {
if ( 'my_taxonomy' === $taxonomy ) {
$args['show_ui'] = false;
}
return $args;
}, 10, 2 );
There is also an "action" you can "hook" into, where this filter is fired just after a taxonomy is registered. Here, you can, for example, assign other post/object type(s) to the taxonomy.
Example code:
/*
* #param string $taxonomy The taxonomy name.
*/
add_action( 'registered_taxonomy', function ( $taxonomy ) {
if ( 'my_taxonomy' === $taxonomy ) {
register_taxonomy_for_object_type( $taxonomy, 'post' );
}
} );
And if you must (or need to) modify the show_ui (or any other options) of a taxonomy after it's registered, then you can use the global $wp_taxonomies, which is an array of all registered taxonomies.
Example code:
/*
* #param string $taxonomy The taxonomy name.
*/
add_action( 'registered_taxonomy', function ( $taxonomy ) {
if ( 'my_taxonomy' === $taxonomy ) {
global $wp_taxonomies;
if ( ! is_array( $wp_taxonomies )
|| ! isset( $wp_taxonomies[ $taxonomy ] ) ) {
return;
}
$wp_taxonomies[ $taxonomy ]->show_ui = false;
}
} );

How to add custom field to custom post type?

Good morning.
I have created a custom post type called 'Products'. I want to create a custom field (is metabox
the correct term?) where my client can tick a box to determine whether a given post within this
CPT is a featured post.
Here is the code in my functions.php to create the 'Products' CPT:
function products_custom_init() {
$labels = array(
'name' => _x('Products', 'post type general name'),
'singular_name' => _x('Product', 'post type singular name'),
'add_new' => _x('Add New', 'products'),
'add_new_item' => __('Add New Product'),
'edit_item' => __('Edit Product'),
'new_item' => __('New Product'),
'view_item' => __('View Product'),
'search_items' => __('Search Products'),
'not_found' => __('Nothing found'),
'not_found_in_trash' => __('Nothing found in Trash'),
'parent_item_colon' => ''
);
$args = array(
'labels' => $labels,
'public' => true,
'publicly_queryable' => true,
'show_ui' => true,
'show_in_menu' => true,
'show_in_nav_menus' => false,
'query_var' => true,
'rewrite' => array('slug','pages'),
'capability_type' => 'post',
'hierarchical' => true,
'menu_position' => 5,
'supports' => array('title','editor','thumbnail','excerpt',)
);
register_post_type( 'products' , $args );
}
add_action( 'init', 'products_custom_init' );
So how do I add the 'featured' metabox / custom field to only Products posts?
Many thanks,
Cynthia
If you want to create a custom meta box inside a custom post type you will need to use 3 functions.
A function to create a custom "meta boxes" block/screen on your post edit screen: add_meta_boxes_{$post_type}
A function to add a input field to change/show your custom meta
And finally a function to save your meta along with the rest of the post when you click save on the post edit screen: save_post_{$post->post_type}
In your case, a custom checkbox would look like this:
add_action( 'add_meta_boxes_products', 'meta_box_for_products' );
function meta_box_for_products( $post ){
add_meta_box( 'my_meta_box_custom_id', __( 'Additional info', 'textdomain' ), 'my_custom_meta_box_html_output', 'products', 'normal', 'low' );
}
function my_custom_meta_box_html_output( $post ) {
wp_nonce_field( basename( __FILE__ ), 'my_custom_meta_box_nonce' ); //used later for security
echo '<p><input type="checkbox" name="is_this_featured" value="checked" '.get_post_meta($post->ID, 'team_member_title', true).'/><label for="is_this_featured">'.__('Featured Product?', 'textdomain').'</label></p>';
}
add_action( 'save_post_team_member', 'team_member_save_meta_boxes_data', 10, 2 );
function team_member_save_meta_boxes_data( $post_id ){
// check for nonce to top xss
if ( !isset( $_POST['my_custom_meta_box_nonce'] ) || !wp_verify_nonce( $_POST['my_custom_meta_box_nonce'], basename( __FILE__ ) ) ){
return;
}
// check for correct user capabilities - stop internal xss from customers
if ( ! current_user_can( 'edit_post', $post_id ) ){
return;
}
// update fields
if ( isset( $_REQUEST['is_this_featured'] ) ) {
update_post_meta( $post_id, 'is_this_featured', sanitize_text_field( $_POST['is_this_featured'] ) );
}
}
As Muhammad Yasin said there are plugins I'd recommend:
http://wordpress.org/extend/plugins/more-fields/
if you want to do it yourself in code look at: add_meta_box
<?php add_meta_box( $id, $title, $callback, $post_type, $context, $priority, $callback_args ); ?>
You can register boxes per post type.
You can use this plugin
http://wordpress.org/extend/plugins/types/
or this tutorial may helpful for you.
http://wptheming.com/2010/08/custom-metabox-for-post-type/

Showing custom taxonomy column in custom posts type listings

I have created a custom post type named banners. Thereby I register a new taxonomy called location that specifies on which page the banner is to be shown. Everything is great however when I click on the custom posts type 'Banner' in the admin window I see all the banners created however the table does not have a column for the taxonomy 'Location'.
In other words I want to be able to see what location the banner is in, in the banners listing.
For those interested, the register_taxonomy register_taxonomy function, as of WordPress 3.5, now offers an argument for show_admin_column (false by default). Set to true, it automatically displays the taxonomy column in the admin.
You can use the manage_post-type_custom_column and manage_edit_post-type_columns filters to add your taxonomy column to the post type listing.
add_action( 'admin_init', 'my_admin_init' );
function my_admin_init() {
add_filter( 'manage_edit-banner_columns', 'my_new_custom_post_column');
add_action( 'manage_banner_custom_column', 'location_tax_column_info', 10, 2);
}
function my_new_custom_post_column( $column ) {
$column['location'] = 'Location';
return $column;
}
function location_tax_column_info( $column_name, $post_id ) {
$taxonomy = $column_name;
$post_type = get_post_type($post_id);
$terms = get_the_terms($post_id, $taxonomy);
if (!empty($terms) ) {
foreach ( $terms as $term )
$post_terms[] ="<a href='edit.php?post_type={$post_type}&{$taxonomy}={$term->slug}'> " .esc_html(sanitize_term_field('name', $term->name, $term->term_id, $taxonomy, 'edit')) . "</a>";
echo join('', $post_terms );
}
else echo '<i>No Location Set. </i>';
}
//what version of wordpress you are using
//since wp 3.5 you can pass parameter show_admin_column=>true
// hook into the init action and call create_book_taxonomies when it fires
add_action( 'init', 'create_book_taxonomies', 0 );
// create two taxonomies, genres and writers for the post type "book"
function create_book_taxonomies() {
// Add new taxonomy, make it hierarchical (like categories)
$labels = array(
'name' => _x( 'Genres', 'taxonomy general name' ),
'singular_name' => _x( 'Genre', 'taxonomy singular name' ),
'search_items' => __( 'Search Genres' ),
'all_items' => __( 'All Genres' ),
'parent_item' => __( 'Parent Genre' ),
'parent_item_colon' => __( 'Parent Genre:' ),
'edit_item' => __( 'Edit Genre' ),
'update_item' => __( 'Update Genre' ),
'add_new_item' => __( 'Add New Genre' ),
'new_item_name' => __( 'New Genre Name' ),
'menu_name' => __( 'Genre' ),
);
$args = array(
'hierarchical' => true,
'labels' => $labels,
'show_ui' => true,
'show_admin_column' => true,
'query_var' => true,
'rewrite' => array( 'slug' => 'genre' ),
);
register_taxonomy( 'genre', array( 'book' ), $args );
}
In addition to Jonathan Wold answer, you can add the ability to filter by your custom taxonomy like this:
add_action('restrict_manage_posts', 'filter_post_type_backend_by_taxonomies', 99, 2);
function filter_post_type_backend_by_taxonomies($post_type, $which) {
if( 'your_post_type' !== $post_type) {
return;
}
$taxonomies = array( 'your_custom_taxonomy' );
foreach( $taxonomies as $taxonomy_slug ) {
$taxonomy_obj = get_taxonomy( $taxonomy_slug );
$taxonomy_name = $taxonomy_obj->labels->name;
$terms = get_terms($taxonomy_slug);
echo "<select name='{$taxonomy_slug}' id='{$taxonomy_slug}' class='postform'>";
echo '<option value="">' . sprintf( esc_html__( 'Show all %s', 'domain-name' ), $taxonomy_name) . '</option>';
foreach ( $terms as $term ) {
printf(
'<option value="%1$s" %2$s>%3$s (%4$s)</option>',
$term->slug,
( ( isset( $_GET[$taxonomy_slug] ) && ( $_GET[$taxonomy_slug] == $term->slug ) ) ? ' selected="selected"' : '' ),
$term->name,
$term->count
);
}
echo '</select>';
}
}

Resources