{"id":424,"date":"2009-09-21T13:12:00","date_gmt":"2009-09-21T20:12:00","guid":{"rendered":"http:\/\/www.shibashake.com\/wordpress-theme\/?page_id=424"},"modified":"2022-01-10T16:39:50","modified_gmt":"2022-01-11T00:39:50","slug":"wordpress-custom-taxonomy-input-panels","status":"publish","type":"post","link":"https:\/\/shibashake.com\/wp\/wordpress-custom-taxonomy-input-panels","title":{"rendered":"WordPress Custom Taxonomy Input Panels"},"content":{"rendered":"<p>Would you like to add new custom fields to your WordPress posts, pages, and categories? Now you can easily do this with the <a href=\"http:\/\/codex.wordpress.org\/Taxonomies\">WordPress custom taxonomy system<\/a>. For example, if you have a blog on movie reviews, you may want to add the fields <em>Actors<\/em> and <em>Genre<\/em> to each of your posts. <\/p>\n<p>What is less clear, however, is how you can expand your WordPress admin interface, so that users can easily enter in these new custom fields. WordPress 2.8+ will only include an input interface for custom taxonomies associated with posts. In addition, this input interface is the standard tag interface, where you must type in the new fields as plain text.<\/p>\n<p>If you are looking for a drop-down menu, or a radio button list, you are out of luck.<\/p>\n<p>Here, we consider how you can flexibly expand your WordPress post interface and style your custom taxonomy input panel however you want.<\/p>\n<div class=\"alignspace\"><\/div>\n<div id='4002' class='wp-caption frame6 alignright' style='width:286px' ><div class='shiba-outer shiba-gallery' ><div class='shiba-stage' style='width:260px'><img loading=\"lazy\" src=\"https:\/\/www.shibashake.com\/wp\/wp-content\/uploads\/2010\/03\/custom-taxonomy1.jpg\" alt=\"\" width=\"260\" height=\"141\" \/><div class='wp-caption-text shiba-caption'>Screen-shot of the tag input interface associated with all custom taxonomies.<\/div><\/div> <!-- End shiba-stage --><\/div><\/div>\n<h2>1. Create Your WordPress Custom Taxonomy<\/h2>\n<p>First, we create a simple test attribute called theme and we associate it with our WordPress posts. We add three initial terms to our new theme attribute &#8211; Beauty, Halloween, and Dragons.<\/p>\n<p>Note that the hierarchical argument simply refers to whether your new theme attribute is a hierarchical structure, such as your WordPress categories, or whether it is flat, such as your WordPress tags.<\/p>\n<p>The hierarchical argument does not currently affect the input interface of your new attribute. As of WordPress 2.8, the normal tag input interface will be used for all custom taxonomy attributes. To restyle the custom taxonomy input interface, you must use the <strong>add_meta_box<\/strong> command.<\/p>\n<p><pre class=\"brush: php; title: ; notranslate\" title=\"\">\r\nadd_action( &#039;init&#039;, &#039;create_theme_taxonomy&#039;, 0 );\r\n\r\nfunction create_theme_taxonomy() {\r\n\tif (!taxonomy_exists(&#039;theme&#039;)) {\r\n\t\tregister_taxonomy( &#039;theme&#039;, &#039;post&#039;, array( &#039;hierarchical&#039; =&gt; false, &#039;label&#039; =&gt; __(&#039;Theme&#039;), &#039;query_var&#039; =&gt; &#039;theme&#039;, &#039;rewrite&#039; =&gt; array( &#039;slug&#039; =&gt; &#039;theme&#039; ) ) );\r\n\r\n\t\twp_insert_term(&#039;Beauty&#039;, &#039;theme&#039;);\r\n\t\twp_insert_term(&#039;Dragons&#039;, &#039;theme&#039;);\r\n\t\twp_insert_term(&#039;Halloween&#039;, &#039;theme&#039;);\r\n\t}\r\n}\r\n<\/pre>\n<\/p>\n<div class=\"alignspace\"><\/div>\n<h2>2. Styling Your Custom Taxonomy Input<\/h2>\n<p>To add input menus to your WordPress post interface, you want to use the WordPress <strong>add_meta_box<\/strong> command. In the example code below, we add a new custom field called Theme into our WordPress post interface. Simply include the code into your <strong>functions.php<\/strong> theme or plugin file.<\/p>\n<p><pre class=\"brush: php; title: ; notranslate\" title=\"\">\r\nfunction add_theme_box() {\r\n\tadd_meta_box('theme_box_ID', __('Theme'), 'your_styling_function', 'post', 'side', 'core');\r\n}\t\r\n\r\nfunction add_theme_menus() {\r\n\r\n\tif ( ! is_admin() )\r\n\t\treturn;\r\n\r\n\tadd_action('admin_menu', 'add_theme_box');\r\n}\r\n\r\nadd_theme_menus();\r\n<\/pre>\n<\/p>\n<div id='15547' class='wp-caption frame6 alignright' style='width:286px' ><div class='shiba-outer shiba-gallery' ><div class='shiba-stage' style='width:260px'><img loading=\"lazy\" src=\"https:\/\/www.shibashake.com\/wp\/wp-content\/uploads\/2022\/01\/custom-taxonomy2.jpg\" alt=\"\" width=\"260\" height=\"145\" \/><div class='wp-caption-text shiba-caption'>Screen-shot of your new drop-down custom taxonomy interface.<\/div><\/div> <!-- End shiba-stage --><\/div><\/div>\n<p>The <strong>add_meta_box <\/strong>function adds <strong>your_styling_function<\/strong> to the WordPress blog system so that it gets called whenever the Edit Post screen is rendered. You can use the same function to add input code to Edit Page and Edit Link screens.<\/p>\n<p>The example <strong>your_styling_function<\/strong> below will add a drop-down menu to your blog Edit Post screen, containing all the current terms on your <em>theme<\/em> custom taxonomy. <\/p>\n<p><pre class=\"brush: php; title: ; notranslate\" title=\"\">\r\n\/\/ This function gets called in edit-form-advanced.php\r\nfunction your_styling_function($post) {\r\n\r\n\techo &#039;&lt;input type=&quot;hidden&quot; name=&quot;taxonomy_noncename&quot; id=&quot;taxonomy_noncename&quot; value=&quot;&#039; . \r\n    \t\twp_create_nonce( &#039;taxonomy_theme&#039; ) . &#039;&quot; \/&gt;&#039;;\r\n\r\n\t\r\n\t\/\/ Get all theme taxonomy terms\r\n\t$themes = get_terms(&#039;theme&#039;, &#039;hide_empty=0&#039;); \r\n\r\n?&gt;\r\n&lt;select name=&#039;post_theme&#039; id=&#039;post_theme&#039;&gt;\r\n\t&lt;!-- Display themes as options --&gt;\r\n    &lt;?php \r\n        $names = wp_get_object_terms($post-&gt;ID, &#039;theme&#039;); \r\n        ?&gt;\r\n        &lt;option class=&#039;theme-option&#039; value=&#039;&#039; \r\n        &lt;?php if (!count($names)) echo &quot;selected&quot;;?&gt;&gt;None&lt;\/option&gt;\r\n        &lt;?php\r\n\tforeach ($themes as $theme) {\r\n\t\tif (!is_wp_error($names) &amp;&amp; !empty($names) &amp;&amp; !strcmp($theme-&gt;slug, $names[0]-&gt;slug)) \r\n\t\t\techo &quot;&lt;option class=&#039;theme-option&#039; value=&#039;&quot; . $theme-&gt;slug . &quot;&#039; selected&gt;&quot; . $theme-&gt;name . &quot;&lt;\/option&gt;\\n&quot;; \r\n\t\telse\r\n\t\t\techo &quot;&lt;option class=&#039;theme-option&#039; value=&#039;&quot; . $theme-&gt;slug . &quot;&#039;&gt;&quot; . $theme-&gt;name . &quot;&lt;\/option&gt;\\n&quot;; \r\n\t}\r\n   ?&gt;\r\n&lt;\/select&gt;    \r\n&lt;?php\r\n}\r\n<\/pre>\n<\/p>\n<p><u>Lines 4-5<\/u> &#8211; Add <a href=\"http:\/\/markjaquith.wordpress.com\/2006\/06\/02\/wordpress-203-nonces\/\">security nonce check<\/a>.<br \/>\n<u>Line 9<\/u> &#8211; We use the <em>hide_empty=0<\/em> argument for the <strong><a href=\"http:\/\/codex.wordpress.org\/Function_Reference\/get_terms\">get_terms<\/a> <\/strong>function so that all <em>theme<\/em> choices will be returned, even the ones that have not yet been assigned to any post.<br \/>\n<u>Line 15<\/u> &#8211; We use the <a href=\"http:\/\/codex.wordpress.org\/Function_Reference\/wp_get_object_terms\"><strong>wp_get_object_terms<\/strong><\/a> function to get the theme currently associated with our post so that we may pre-select it in our drop-down menu.<br \/>\n<u>Lines 17-25<\/u> &#8211; Render our drop-down menu, populating it with our theme names.<br \/>\n<strong>Note<\/strong> &#8211; On lines 22 and 24, we are now setting the <em>theme-option<\/em> value to <strong>$theme->slug<\/strong>. As pointed out by <a href=\"http:\/\/archgfx.net\/\">Adam<\/a> in the <a href=\"http:\/\/shibashake.com\/wordpress-theme\/wordpress-custom-taxonomy-input-panels#comment-1684\">comments section<\/a>, the taxonomy object slug is unique (unlike its name), and this will prevent duplicate taxonomy terms from being created.<\/p>\n<div id='15548' class='wp-caption frame6 aligncenter' style='width:546px' ><div class='shiba-outer shiba-gallery' ><div class='shiba-stage' style='width:520px'><img loading=\"lazy\" alt=\"\" src=\"https:\/\/www.shibashake.com\/wp\/wp-content\/uploads\/2022\/01\/custom-taxonomy3.jpg\" width=\"520\" height=\"598\" \/>\n<div class='wp-caption-text shiba-caption'>Screen-shot of the Edit Post, which now has the old tag input box and the new drop-down menu box.<\/div><\/div> <!-- End shiba-stage --><\/div><\/div>\n<p>Note that when you add your new drop-down menu box, the old tag input box will still appear. To only include one input box, use the <strong>remove_meta_box<\/strong> command as suggested by <a href=\"http:\/\/wordpressbar.com\/\">Leo Mysor<\/a> in the comments section below.<\/p>\n<p><pre class=\"brush: php; title: ; notranslate\" title=\"\">\r\nremove_meta_box('tagsdiv-theme','post','core');\r\n<\/pre>\n<\/p>\n<p><strong><a href=\"http:\/\/wordpress.stackexchange.com\/questions\/6183\/how-do-you-remove-a-category-style-hierarchical-taxonomy-metabox\">Note<\/a><\/strong> &#8211; For non-hierarchical taxonomies (like tags) you want to use tagsdiv-{$taxonomy_name}, e.g. <em>tagsdiv-theme<\/em>. For hierarchical taxonomies (like categories) you want to use {$taxonomy_name}div, e.g. <em>themediv<\/em>.<\/p>\n<p>You can add the <strong>remove_meta_box command<\/strong> before your <strong>add_meta_box<\/strong> statement. <\/p>\n<p>Alternatively, you can register your custom taxonomy attribute to something other than &#8216;post&#8217;. In the code example below, we register our theme custom taxonomy to <em>shiba_post<\/em>, which gets rid of the standard tag input box in the Edit Post screen.<\/p>\n<p><pre class=\"brush: php; title: ; notranslate\" title=\"\">\r\nregister_taxonomy( &#039;theme&#039;, &#039;shiba_post&#039;, array( &#039;hierarchical&#039; =&gt; false, &#039;label&#039; =&gt; __(&#039;Theme&#039;), &#039;query_var&#039; =&gt; &#039;theme&#039;, &#039;rewrite&#039; =&gt; array( &#039;slug&#039; =&gt; &#039;theme&#039; ) ) );\r\n<\/pre>\n<\/p>\n<p>However, as pointed out by Leo, this also removes your taxonomy tab from the Posts menu and makes it difficult for others to add new items to your taxonomy.<\/p>\n<div class=\"alignspace\"><\/div>\n<h2>3. Saving Your New Inputs<\/h2>\n<p>Now, we can insert any input panel we want for our custom taxonomy, however, we still need a way to save those input values. This can be achieved with the <strong>save_post<\/strong> WordPress hook. This hook allows you to execute a function of your choice when a WordPress post gets saved. There are similar hooks for saving pages and links.<\/p>\n<p>Just add the <strong>save_post<\/strong> hook to your existing add_theme_menus function. For example, the code below registers the <strong>save_taxonomy_data function<\/strong> with the WordPress blog system so that it gets executed whenever a WordPress post is saved or updated.<\/p>\n<p><pre class=\"brush: php; title: ; notranslate\" title=\"\">\r\nfunction add_theme_menus() {\r\n\r\n\tif ( ! is_admin() )\r\n\t\treturn;\r\n\r\n\tadd_action('admin_menu', 'add_theme_box');\r\n\r\n\t\/* Use the save_post action to save new post data *\/\r\n\tadd_action('save_post', 'save_taxonomy_data');\r\n}\r\n<\/pre>\n<\/p>\n<p>Now, you just need to specify your <b>save_taxonomy_data<\/b> function. We can adapt our own save function from the <a href=\"http:\/\/codex.wordpress.org\/Function_Reference\/add_meta_box\">add_meta_data example on WordPress.org<\/a>.<\/p>\n<p><pre class=\"brush: php; title: ; notranslate\" title=\"\">\r\nfunction save_taxonomy_data($post_id) {\r\n\/\/ verify this came from our screen and with proper authorization.\r\n\r\n \tif ( !wp_verify_nonce( $_POST[&#039;taxonomy_noncename&#039;], &#039;taxonomy_theme&#039; )) {\r\n    \treturn $post_id;\r\n  \t}\r\n\r\n  \t\/\/ verify if this is an auto save routine. If it is our form has not been submitted, so we dont want to do anything\r\n  \tif ( defined(&#039;DOING_AUTOSAVE&#039;) &amp;&amp; DOING_AUTOSAVE ) \r\n    \treturn $post_id;\r\n\r\n  \r\n  \t\/\/ Check permissions\r\n  \tif ( &#039;page&#039; == $_POST[&#039;post_type&#039;] ) {\r\n    \tif ( !current_user_can( &#039;edit_page&#039;, $post_id ) )\r\n      \t\treturn $post_id;\r\n  \t} else {\r\n    \tif ( !current_user_can( &#039;edit_post&#039;, $post_id ) )\r\n      \treturn $post_id;\r\n  \t}\r\n\r\n  \t\/\/ OK, we&#039;re authenticated: we need to find and save the data\r\n\t$post = get_post($post_id);\r\n\tif (($post-&gt;post_type == &#039;post&#039;) || ($post-&gt;post_type == &#039;page&#039;)) { \r\n           \/\/ OR $post-&gt;post_type != &#039;revision&#039;           $theme = $_POST[&#039;post_theme&#039;];\r\n\t   wp_set_object_terms( $post_id, $theme, &#039;theme&#039; );\r\n        }\r\n\treturn $theme;\r\n\r\n}\r\n<\/pre>\n<\/p>\n<p><u>Lines 4-6<\/u> &#8211; First we do a <i>nonce<\/i> check to ensure that the function is being called by our very own <b>your_styling_function<\/b>. Make sure that the <em>taxonomy_noncename<\/em> and <em>taxonomy_theme<\/em> terms match those that were created earlier, on lines 4-5 in <b>your_styling_function<\/b>.<\/p>\n<p><u>Lines 9-10<\/u> &#8211; Take no action for auto-saves.<\/p>\n<p><u>Lines 14-20<\/u> &#8211; Check that the current user has proper permissions to edit posts.<\/p>\n<p><u>Lines 23-28<\/u> &#8211; Associates our post with the new theme taxonomy data. It is important to do a <em>post_type<\/em> check here, because this function will also get called on post <em>revision<\/em> objects. <\/p>\n<p>As pointed out by <a href=\"http:\/\/shibashake.com\/wordpress-theme\/wordpress-custom-taxonomy-input-panels#comment-1046\">Angelia<\/a>, this results in double counting the newly added taxonomy relationship. <\/p>\n<div class=\"alignspace\"><\/div>\n<h2>4. Getting a Taxonomy Term Count<\/h2>\n<p>If you want to get the count of a particular taxonomy term, i.e., the number of objects that it is associated with, you can easily extract that figure from the <a href=\"http:\/\/codex.wordpress.org\/WordPress_Taxonomy\">WordPress <em>term_taxonomy<\/em> database<\/a>.<\/p>\n<p>Just add the count code into the <em>foreach $themes loop<\/em>.<\/p>\n<p><pre class=\"brush: php; title: ; notranslate\" title=\"\">\r\nglobal $wpdb;\r\nforeach ($themes as $theme) {\r\n\r\n        $count = $wpdb-&gt;get_var( $wpdb-&gt;prepare( &quot;SELECT count FROM $wpdb-&gt;term_taxonomy WHERE term_taxonomy_id = %d&quot;, $theme-&gt;term_taxonomy_id) );\r\n\r\n        \/* Your code here to display the count ... *\/\r\n}\r\n<\/pre>\n<\/p>\n<p>While registering your custom taxonomy, you can link an <em>update_count_callback<\/em> function to it. This function will get called every time any term in your taxonomy gets a count update. This allows you to control what actually gets stored in the <em>count<\/em> column of your custom taxonomy terms.<\/p>\n<p><pre class=\"brush: php; title: ; notranslate\" title=\"\">\r\n$args = array( &#039;hierarchical&#039; =&gt; false, \r\n               &#039;update_count_callback&#039; =&gt; &#039;test_taxonomy_count&#039;, \r\n               &#039;label&#039; =&gt; __(&#039;Theme&#039;), \r\n               &#039;query_var&#039; =&gt; &#039;theme&#039;, \r\n               &#039;rewrite&#039; =&gt; array( &#039;slug&#039; =&gt; &#039;theme&#039; ) )\r\nregister_taxonomy( &#039;theme&#039;, &#039;post&#039;,  $args);\r\n\r\n\/\/ This test count function just does the default WordPress operations\r\nfunction test_taxonomy_count($terms) {\r\n\tglobal $wpdb;\r\n\t$terms = array_map(&#039;intval&#039;, $terms);\r\n\t\r\n\tforeach ( (array) $terms as $term) {\r\n\t\t$count = $wpdb-&gt;get_var( $wpdb-&gt;prepare( &quot;SELECT COUNT(*) FROM $wpdb-&gt;term_relationships WHERE term_taxonomy_id = %d&quot;, $term) );\r\n\t\t$wpdb-&gt;update( $wpdb-&gt;term_taxonomy, compact( &#039;count&#039; ), array( &#039;term_taxonomy_id&#039; =&gt; $term ) );\r\n\t}\r\n}\r\n<\/pre>\n<\/p>\n<div class=\"alignspace\"><\/div>\n<h2>5. All Done!<\/h2>\n<p>You can use the same code to style your custom taxonomy input panels for pages and links. Just change the <em>post<\/em> attribute to <em>page<\/em> or <em>link<\/em> when calling <strong>add_meta_box<\/strong> and use the <em>save_page<\/em>, <em>edit_link<\/em>, and <em>add_link<\/em> hooks instead of <em>save_post<\/em>.<\/p>\n<p>You can also <a href=\"http:\/\/shibashake.com\/wordpress-theme\/expand-the-edit-category-admin-panel\">add new fields to your WordPress blog categories<\/a> using a similar system.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>We describe registering custom taxonomies, and how to add our own custom taxonomy input interface. Substitute the default tag interface with a drop-down menu, radio button list, or something else. <\/p>\n","protected":false},"author":1,"featured_media":4002,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_genesis_hide_title":false,"_genesis_hide_breadcrumbs":false,"_genesis_hide_singular_image":false,"_genesis_hide_footer_widgets":false,"_genesis_custom_body_class":"","_genesis_custom_post_class":"","_genesis_layout":""},"categories":[1174,1175],"tags":[1113,145,1114,1115,1111,1112,144,1116,1118,1117,1120,1119,573],"_links":{"self":[{"href":"https:\/\/www.shibashake.com\/wp\/wp-json\/wp\/v2\/posts\/424"}],"collection":[{"href":"https:\/\/www.shibashake.com\/wp\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.shibashake.com\/wp\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.shibashake.com\/wp\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.shibashake.com\/wp\/wp-json\/wp\/v2\/comments?post=424"}],"version-history":[{"count":95,"href":"https:\/\/www.shibashake.com\/wp\/wp-json\/wp\/v2\/posts\/424\/revisions"}],"predecessor-version":[{"id":15549,"href":"https:\/\/www.shibashake.com\/wp\/wp-json\/wp\/v2\/posts\/424\/revisions\/15549"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.shibashake.com\/wp\/wp-json\/wp\/v2\/media\/4002"}],"wp:attachment":[{"href":"https:\/\/www.shibashake.com\/wp\/wp-json\/wp\/v2\/media?parent=424"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.shibashake.com\/wp\/wp-json\/wp\/v2\/categories?post=424"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.shibashake.com\/wp\/wp-json\/wp\/v2\/tags?post=424"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}