This is a follow up to this post, outlining why I can not use the get_terms function while in functions.php (actually calling via ajax/admin_ajax.php).

I can grab the terms (custom tax) on any post, on any page, except when in my ajax function. I receive the dreaded 'taxonomy does not exist' error when dumping the value of get_terms.

The problem is, the taxonomy is registered after I call the function to find the terms.

The question is, how do I register the tax early enough so I can use this function? My code to register the custom post type and taxonomy is first in my functions.php (included via an external php to keep functions.php clean)

* 1.0 ------------------ Events ----------------

// 1. Custom Post Type Registration (Events)
add_action( 'init', 'create_event_postype', 0 );

function create_event_postype() {
  $labels = array(
    'name' => _x('Events', 'post type general name'),
    'singular_name' => _x('Event', 'post type singular name'),
    'add_new' => _x('Add New', 'events'),
    'add_new_item' => __('Add New Event'),
    'edit_item' => __('Edit Event'),
    'new_item' => __('New Event'),
    'view_item' => __('View Event'),
    'search_items' => __('Search Events'),
    'not_found' =>  __('No events found'),
    'not_found_in_trash' => __('No events found in Trash'),
    'parent_item_colon' => '',

$args = array(
    'label' => __('Events'),
    'labels' => $labels,
    'public' => true,
    'can_export' => true,
    'show_ui' => true,
    '_builtin' => false,
    '_edit_link' => 'post.php?post=%d', // ?
    'capability_type' => 'post',
    'menu_icon' => get_bloginfo('template_url').'/images/icons/events.png',
    'hierarchical' => false,
    'rewrite' => array( "slug" => "events" ),
    'supports'=> array('title', 'thumbnail', 'excerpt', 'editor', 'custom-fields') ,
    'show_in_nav_menus' => true,
    'taxonomies' => array('post_tag', 'tf_eventtype')

register_post_type( 'tf_events', $args);


// 2. Custom Taxonomy Registration (Event Types)
add_action( 'init', 'create_eventtype_taxonomy', 0 );
function create_eventtype_taxonomy() {

  $labels = array(
    'name' => _x( 'Event Type', 'taxonomy general name' ),
    'singular_name' => _x( 'Event Type', 'taxonomy singular name' ),
    'search_items' =>  __( 'Search Event Types' ),
    'popular_items' => __( 'Popular Event Types' ),
    'all_items' => __( 'All Event Types' ),
    'parent_item' => null,
    'parent_item_colon' => null,
    'edit_item' => __( 'Edit Event Type' ),
    'update_item' => __( 'Update Event Type' ),
    'add_new_item' => __( 'Add New Event Type' ),
    'new_item_name' => __( 'New Event Type Name' ),
    'separate_items_with_commas' => __( 'Separate event types with commas' ),
    'add_or_remove_items' => __( 'Add or remove event types' ),
    'choose_from_most_used' => __( 'Choose from the most used event types' ),

register_taxonomy('tf_eventtype','tf_events', array(
    'label' => __('Event Type'),
    'labels' => $labels,
    'hierarchical' => true,
    'show_ui' => true,
    'query_var' => true,
    'rewrite' => array( 'slug' => 'event-type' ),

Here is some pseudo code to show how I'm calling this function

from a custom page, I call a function via AJAX (ajax-admin.php)

            type: "POST",  
            url: "<? bloginfo('url'); ?>/wp-admin/admin-ajax.php", //Built in WP AJAX
            data: data, 
            success:  function(data){
                         //console.log('search complete');

Here is the function that calls a custom query, and where get_terms fails.

* 1.0 Calendar AJAX Queries
// if both logged in and not logged in users can send this AJAX request,
// add both of these actions, otherwise add only the appropriate one
add_action( 'wp_ajax_nopriv_calendar_search', 'calendar_search' );
add_action( 'wp_ajax_calendar_search', 'calendar_search' );

function calendar_search() {        
        $args = array(
            'post_type' => 'tf_events',         
            'post_status' => 'publish',
            'order' => 'ASC'

        $query = new WP_Query( $args ); 

        // - loop start -
        if ( $query->have_posts() ) {

         while ($query->have_posts()) : $query->the_post(); /*Shows the posts that are available. */

                //Event Type
                $cats = get_the_terms($post->ID , 'tf_eventtype'); //the function that fails. All other custom data works fine 

                '<article class="post" id="post-'. $post->ID . '"  itemscope itemtype="http://schema.org/Event">                       
                   <h2  itemprop="name" class="entry-title"><a href="' . get_permalink() .'">'. get_the_title() . '</a></h2>                
                   <div class="entry">
                     <p itemprop="location">';
                       if($cats) foreach($cats as $cat){ 
                            echo " | " . $cat->name;

         } else {
            echo "<h2 class='month'>Sorry, no events found!</h2>";            
        die(); // this is required to return a proper result      


  • 2
    Show us where you are attempting to use get_terms. init action should run before any properly hooked ajax requests.
    – Milo
    Commented Oct 17, 2013 at 16:02
  • +1 for @Milo. init action is triggered before wp_ajax_* actions. After that, using functions.php earlier hook available is after_setup_theme.
    – gmazzap
    Commented Oct 17, 2013 at 16:05
  • I have a custom calendar page and an ajax call queries the database (wp_query). I use get_terms inside the custom query, inside my ajax-functions include. How can I show you this code? page-calendar.php > ajax call through admin-ajax.php > custom wp_query > get_terms inside the loop
    – Nate
    Commented Oct 17, 2013 at 16:13
  • Just added the ajax call and the functions that get called. Yes, I include the files, only to keep my functions.php cleaner.
    – Nate
    Commented Oct 17, 2013 at 16:24
  • What is odd, is I can manually call get_terms (passing a post ID) anywhere else on my page - it only fails when inside my calendar_search() function
    – Nate
    Commented Oct 17, 2013 at 16:27

3 Answers 3


So, thanks to G. M.'s help I was able to debug the problem more efficiently, now that I knew init was indeed not being called. I started stripping out all extraneous functions from my functions.php file and I realized I called do_action twice, as I have many functions run through admin-ajax.php. The do_action calls must only be used once! Odd how the bug presented itself!

$action = isset($_POST['action']) ? $_POST['action'] : null;

//These functions take an ajax call and then call the appropriate PHP function
// this hook is fired if the current viewer is not logged in
do_action( 'wp_ajax_nopriv_' . $action );
do_action( 'wp_ajax_' . $action );
  • 1
    how do you have things set up where you have to manually call do_action to fire ajax callbacks? you're doing something strange.
    – Milo
    Commented Oct 18, 2013 at 0:03
  • Strange isn't good, so please let me know if you have a better suggestion. Basically, the do_action routes the ajax call to the different php functions in functions.php (using add_action). Tutorial was from here, under "Best Practices"
    – Nate
    Commented Oct 18, 2013 at 14:33
  • I don't think they're telling you to add that code, that's the code that's in admin-ajax.php that fires your ajax callback, see it in source here.
    – Milo
    Commented Oct 18, 2013 at 14:55

Just add global $post; before use $post variable:

while ($query->have_posts()) : $query->the_post();
  global $post;
  $cats = get_the_terms($post->ID , 'tf_eventtype');
  //... and so on
  • I wish it were that easy! Still getting the same error. object(WP_Error)#188 (2) { ["errors"]=> array(1) { ["invalid_taxonomy"]=> array(1) { [0]=> string(16) "Invalid taxonomy" } } ["error_data"]=> array(0) { } }
    – Nate
    Commented Oct 17, 2013 at 16:45
  • Your code work for me (after adding global $post;), I've tested. Are you sure that the file with code that register taxonomy is included? Try to add a die on first line, what happen? @Nate
    – gmazzap
    Commented Oct 17, 2013 at 16:50
  • die() on the first line of calendar_search()? I will try right now. Yes, there might be another culprit involved. I have used this same code on another site and have never seen the particular error.
    – Nate
    Commented Oct 17, 2013 at 16:59
  • Yes, die() kills the script both on calendar_search() and before I register my taxonomy. Again, get_terms works everywhere on the page/site except in this one function.
    – Nate
    Commented Oct 17, 2013 at 17:03
  • Try to put if ( did_action('init') ) die('inited'); as 1st line of calendar_search() function. It will prove init is performed and problem is elsewhere, even if I can't see where...
    – gmazzap
    Commented Oct 17, 2013 at 17:23

The "invalid taxonomy" message occurs because when the ajax call is made, not all the taxonomies have been registered because all the plugins have not been initialized.

the solution is to launch the hook ajax after the initialization and so it works ok


        add_action( 'init', function() {

            //add the ajax hook only when all the taxonomies have been registered
            add_action('wp_ajax_my_action',  function() {

                $result = get_terms( 'my_taxonomy_name' );

        }, 99);

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.