How can I add programmatically custom taxonomy terms to a custom type post when saving posts?

Scenario: there is a ‘Recommended Books’ section on the website which uses the ‘book’ custom post type and the ‘author’ custom taxonomy. I’m using Amazon Product Advertising API for retrieving book data and covers. When adding a new ‘book’ into WordPress, the user copies the book ID (ASIN) into the post edit field, and clicks ‘Publish’. Then, when saving the post, the post title (book title) and the author taxonomy term should be programmatically filled in through Amazon. (These are used to offer ‘Order by’ functionality on the front end.)

Currently I’m using wp_insert_post_data to hook into the ‘book’ saving process, and the wp_set_object_terms function to try to add the custom taxonomy term to the ‘book’.

The problem is: the wp_set_object_terms function doesn’t seem to work. It won’t add anything, albeit returns an array which, according to Codex, should mean success. Though the returning array is odd (as far as I see). When using post ID 107 and term ID 3 (instead of an author string, for testing purposes) the returning array displays the following with print_r:

Array
(
[0] => 3
)

(Also tried with wp_set_post_terms, and it makes no difference.)

My complete function:

// Function to automatically retrieve and store Amazon Book data (title and author) when adding 'book' type posts
if( function_exists('asa_item') ) {
    add_filter( 'wp_insert_post_data', 'filter_handler', '99', 2 );
    function filter_handler( $data , $postarr ) {

        // Proceed only if book is added/edited
        if ( $postarr['post_type'] !== 'book')
            return $data;

        // Try to Extract ASIN from post body; ignore everything else
        if ( preg_match( '/([0-9A-Z]{10})/', $data['post_content'],  $matches) ) {
            // Successful, store ASIN
            $book_asin = $matches[0];
            // Wrap ASIN in AmazonSimpleAdmin shortcode (with 'cover' template) automatically for user convenience
            $data['post_content'] = '[asa cover]' . $matches[0] . '[/asa]';
        } else {
            // Unsuccessful: set to draft, return and show error message
            $data['post_status'] = 'draft';
            add_filter('redirect_post_location', 'my_redirect_post_location_filter_1', 99);
            return $data;
        }

        // Retrieve and store book data from Amazon with AmazonSimpleAdmin plugin
        $book_data = explode( "<sep>", asa_get_item( $book_asin, 'book_data' ) );
        /******************
         * index 0 = title
         * index 1 = author
         ******************/

        // Check data; if no data, set to draft, return and show error message
        if ( $book_data[0] == '' ) {
            $data['post_status'] = 'draft';
            add_filter('redirect_post_location', 'my_redirect_post_location_filter_2', 99);
            return $data;
        }

        // Fill in Post Title with Amazon data if empty
        if ( $data['post_title'] == '' )
            $data['post_title'] = $book_data[0];

        // Fill in Author tag with Amazon data if missing
        if ( ! has_term( $book_data[1], 'author', $postarr['ID'] ) ) {
            wp_set_object_terms( $postarr['ID'], $book_data[1], 'author' );
        }

        return $data;
    }
}

1 Answer
1

So, to answer my own question:

I haven’t found any solution inside wp_insert_post_data. I suspect that the problem is connected to the fact that when wp_insert_post_data is executed the post in question is not yet in the database. And albeit I didn’t manage to find it in taxonomy.php, it is logical to assume that the wp_set_post_terms function have some checking mechanism to avoid inserting term relationships with arbitrary/non-existent post ID’s.

Anyhow, in wp_insert_post_data I defined a global variable to store the tax term which needs to be added (instead of trying to add it locally). Then I hooked into save_post, which is executed after the post have been saved, and retrieved/inserted the term from there.

Seem to work just fine.

The relevant code part in wp_insert_post_data:

...

// Fill in Author tag with Amazon data if missing
if ( ! has_term( $book_data[1], 'author', $postarr['ID'] ) ) {
    global $add_this_tax_term_to_book;
    $add_this_tax_term_to_book[] = $book_data[1];
    $add_this_tax_term_to_book[] = 'author';
}

...

And the code for save_post:

add_action('save_post', 'add_my_tax_term');
function add_my_tax_term( $post_id ) {
    global $add_this_tax_term_to_book;

    if ( !(empty( $add_this_tax_term_to_book )) ) {
        wp_set_object_terms( $post_id, $add_this_tax_term_to_book[0], $add_this_tax_term_to_book[1] );
}

Leave a Comment