Made this custom taxonomy that'll control layout on single posts, basically I want to add two options, Layout 1 and Layout 2.

// Register Custom Taxonomy
function custom_taxonomy() {

    $labels = array(
        'name'                       => _x( 'Layout', 'Taxonomy General Name', 'text_domain' ),
        'singular_name'              => _x( 'Layout', 'Taxonomy Singular Name', 'text_domain' ),
        'menu_name'                  => __( 'Taxonomy', 'text_domain' ),
        'all_items'                  => __( 'All Items', 'text_domain' ),
        'parent_item'                => __( 'Parent Item', 'text_domain' ),
        'parent_item_colon'          => __( 'Parent Item:', 'text_domain' ),
        'new_item_name'              => __( 'New Item Name', 'text_domain' ),
        'add_new_item'               => __( 'Add New Item', 'text_domain' ),
        'edit_item'                  => __( 'Edit Item', 'text_domain' ),
        'update_item'                => __( 'Update Item', 'text_domain' ),
        'separate_items_with_commas' => __( 'Separate items with commas', 'text_domain' ),
        'search_items'               => __( 'Search Items', 'text_domain' ),
        'add_or_remove_items'        => __( 'Add or remove items', 'text_domain' ),
        'choose_from_most_used'      => __( 'Choose from the most used items', 'text_domain' ),
        'not_found'                  => __( 'Not Found', 'text_domain' ),
    $capabilities = array(
        'manage_terms' => 'foobar',
        'edit_terms'   => 'foobar',
        'delete_terms' => 'foobar',
        'assign_terms' => 'foobar' 
    $args = array(
        'labels'                     => $labels,
        'hierarchical'               => true,
        'public'                     => true,
        'show_ui'                    => true,
        'show_admin_column'          => false,
        'show_in_nav_menus'          => false,
        'show_tagcloud'              => false,
        'capabilities'               => $capabilities,
    register_taxonomy( 'Layout', array( 'post' ), $args );


// Hook into the 'init' action
add_action( 'init', 'custom_taxonomy', 0 );

Capabilities are set to invalid values to stop terms from being edited, but I can't get wp_insert_term working.

Adding two terms to my custom taxonomy can't be so hard, right?

Using this to insert a term doesn't work, although if I changed my custom taxonomy name to 'category', ie WP default it works just fine. What gives?

function example_insert_category() {
    $parent_term = term_exists( 'layout' ); // array is returned if taxonomy is given
$parent_term_id = $parent_term['term_id']; // get numeric term id
        'Example Category',
          'description' => 'This is an example category created with wp_insert_term.',
          'slug'        => 'example-category'
add_action( 'after_setup_theme', 'example_insert_category' );
  • As promised, I posted the code to the plugin. Hope this helps :-) Oct 7, 2014 at 16:03

1 Answer 1



As promised, here is the code to the plugin.

It is a known fact that custom taxonomies and custom post types should go into a plugin, and not in your theme. I have stripped parts from my plugin.


The taxonomy is registered as normal through the plugin. For any info regarding this, you can go and check out register_taxonomy. The part that I needed to highlight and what is relevant to this question, is how to insert new terms.

To insert terms through wp_insert_terms are quick and easy, but this code can also hurt loading time if not used correctly. The idea is to run that function once, and then never again, almost like removing it after the first run.

To accomplish this, you are going to hook your function to register_activation_hook. This hook runs once, that is when the plugin is activated, it will not rerun on page refresh. The only time it will fire again is when the plugin is deactivated and activated again

So you first need to register your taxonomy as you can't assign terms to a taxonomy that does not exists. Once your taxonomy is registered, you can insert your terms. Remember, this action will only take place once, and that is when the plugin is activated. If you need to add terms, you need to deactivate the plugin and activate it again

You want to also first check if a term exists before trying to create and insert it.

Here is the plugin code

Plugin Name: Create terms
Plugin URI: http://wordpress.stackexchange.com/q/163541/31545
Description: Create terms
Version: 1.0
Author: Pieter Goosen
License: GPLv2 or later
class Test_Terms {

    function __construct() {
        register_activation_hook( __FILE__,array( $this,'activate' ) );
        add_action( 'init', array( $this, 'create_cpts_and_taxonomies' ) );

    function activate() {

    function create_cpts_and_taxonomies() {

        $args = array( 
            'hierarchical'                      => true,  
            'labels' => array(
                'name'                          => _x('Test Tax', 'taxonomy general name' ),
                'singular_name'                 => _x('Test Tax', 'taxonomy singular name'),
                'search_items'                  => __('Search Test Tax'),
                'popular_items'                 => __('Popular Test Tax'),
                'all_items'                     => __('All Test Tax'),
                'edit_item'                     => __('Edit Test Tax'),
                'edit_item'                     => __('Edit Test Tax'),
                'update_item'                   => __('Update Test Tax'),
                'add_new_item'                  => __('Add New Test Tax'),
                'new_item_name'                 => __('New Test Tax Name'),
                'separate_items_with_commas'    => __('Seperate Test Tax with Commas'),
                'add_or_remove_items'           => __('Add or Remove Test Tax'),
                'choose_from_most_used'         => __('Choose from Most Used Test Tax')
            'query_var'                         => true,  
            'rewrite'                           => array('slug' =>'test-tax')        
        register_taxonomy( 'test_tax', array( 'post' ), $args );

    function register_new_terms() {
        $this->taxonomy = 'test_tax';
        $this->terms = array (
            '0' => array (
                'name'          => 'Tester 1',
                'slug'          => 'tester-1',
                'description'   => 'This is a test term one',
            '1' => array (
                'name'          => 'Tester 2',
                'slug'          => 'tester-2',
                'description'   => 'This is a test term two',

        foreach ( $this->terms as $term_key=>$term) {
                        'description'   => $term['description'],
                        'slug'          => $term['slug'],
            unset( $term ); 

$Test_Terms = new Test_Terms();


Your problem with inserting terms is your hook. after_setup_theme runs before init, meaning that you are trying to insert a term to a taxonomy that is not registered yet.

I would suggest that you move your wp_insert_term function to inside your init function, just below register_taxonomy

It is also advisable to first check if a term exists (term_exists) before inserting it


// Register Custom Taxonomy
function custom_taxonomy() {


   if( !term_exists( 'Example Category', 'layout' ) ) {
           'Example Category',
             'description' => 'This is an example category created with wp_insert_term.',
             'slug'        => 'example-category'

// Hook into the 'init' action
add_action( 'init', 'custom_taxonomy', 0 );

Please note, this is untested


Custom taxonomy names (and custom post type names) need to comply to a very specific set of rules, otherwise you will encounter pitfalls that there are no work around for.

Here is a guide line when choosing names for custom taxonomies (and custom post types)

  1. The following are not allowed in custom taxonomy names and custom post type names

    • Capital letters or camelcase

    • Any type of special character, except underscores (_)

    • Spaces

    • More than 32 characters for taxonomies and 20 for post types

    • Any reserved names, and please note, this goes for any custom naming convention, not just taxonomy names.

  2. If there are more than one word in a taxonomy name, they have to be separated by underscores, not hyphens (-). I have been challenged that hyphens are the way to go for SEO in URL's for taxonomy names. It is true, that is why there are rewrite rules to adjust your URL accordingly. Never change taxonomy names or post type names for URL SEO purposes

Also, you should remove that weird capabilities. It might also create a problem

If this does not solve your issue, please add the code that you use with wp_insert_term


  • After looking into the source I'm a bit stumped, because the $taxonomy parameter does not get sanitized at all, if the query_var argument gets set to true. Thats quite unbelievable actually. And otherwise it gets sanitized via sanitize_title_with_dashes(), which will, nomen es omen, replace stuff with dashes all over the place. Which is unbelievable too, as they shouldn't be used. Oct 6, 2014 at 18:23
  • Aside from the fact, you can use numbers as you like, anywhere, so in the beginning too, although you can read everywhere that this shouldn't be done. Couldn't find a definite reason against numbers though. Unlike for dashes, were at least there is a statement »Also, if the post type contains dashes you will not be able to add columns to the custom post type's admin page (using the 'manage_<Custom Post Type Name>_posts_columns' action).« on the codex page of register_post_type(). Oct 6, 2014 at 18:24
  • 1
    Wordpress does have its flaws, must agree. Some are actual crimes :-). I think dashes is one of the most talked subject and also most used in names. Its failure is quite evident when you start looking at the template hierarchy. Create a taxonomy with two words like my-taxonomy separated by a dash, and create a taxonomy template taxonomy-my-taxonomy.php and you'll see failure. I have read the number thing somewhere, need to recheck that again though. This is a stay safe list that I always use to stay safe, and it has worked perfectly. Thanks for all your info, appreciated Oct 6, 2014 at 18:41
  • 1
    As do I, but just because I learned it from the beginning the right way. As I learned the most I know from WordPress Development and the smart and experienced people on here. So there are a lot of mistakes I never actually made myself. Oct 6, 2014 at 18:48
  • 1
    Imho should this answer be protected. Details in this answer/example are very important and it is not often enough pointed at in the Codex.
    – Charles
    Nov 22, 2015 at 16:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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