Bulk import in custom taxonomy

The Function: Add new terms and term meta values from .csv file below should help.

1. Requirements

The .csv file must have a header row.

The function below is defined to receive a .csv with a minimum of three columns to fill these WP_Term fields:

  1. name,
  2. slug, and
  3. description.

However, the suggested function updates and variable configurations below should accommodate a two-column .csv.

2. Suggested function updates

Since your .csv file might only have two columns (title, url), you could change these lines from:

'description' => \__( $taxonomy_term[ $taxonomy_term_description ], 'translation_domain' ),
'slug'        => $taxonomy_term[ $slug ],

…to…

'description' => '',
'slug'        => $taxonomy_term[ $taxonomy_term_name ],

…which reuses the $taxonomy_term_name column for the slug value.

You could use a function like preg_replace() to replace invalid slug characters. But, nothing needs to be done if you are ok with how WordPress sanitizes the term slug.

3. Variable configurations

Update the variables in the function for your .csv by using:

// Custom taxonomy name.
$custom_taxonomy = 'TYPE YOUR CUSTOM TAXONOMY NAME HERE';

// .csv column header for the term_name.
$taxonomy_term_name="title";

// .csv column header for the term_description.
$taxonomy_term_description = 'title';

// .csv column header for the slug.
$slug = 'title';

// Provide the absolute file path to your .csv on this line in the function below.
$file_path = __DIR__ . '/file.csv'; 

The url column will be added to the Term Meta.

Function: Add new terms and term meta values from .csv file

/**
 * Add new terms and term meta values from .csv file.
 *
 * The .csv file must contain column headers for the
 * term_name, term_description, and slug.
 *
 * Update the $custom_taxonomy, $taxonomy_term_name,
 * $taxonomy_term_description and $slug variables
 * with the appropriate values.
 *
 * @param string $file_path
 *
 * @return void
 */
function create_taxonomy_terms( $file_path="" ) {
    // Custom taxonomy name.
    $custom_taxonomy = 'CUSTOM_TAXONOMY';

    // .csv column header for the term_name.
    $taxonomy_term_name="taxonomy_term_name";

    // .csv column header for the term_description.
    $taxonomy_term_description = 'taxonomy_term_description';

    // .csv column header for the slug.
    $slug = 'slug';

    // .csv column header for a column that contains newline characters.
    // This column will be stored in term meta.
    $column_with_newlines="csv_header_for_column_containing_newline_characters";

    // For hard-coded file paths.
    if ( empty( $file_path ) ) {
          $file_path = __DIR__ . '/file.csv';
    }

    try {
        $rows = array_map( 'str_getcsv', file( $file_path ) );

        $headers = array_shift( $rows );

        $taxonomy_terms = array();
        foreach ( $rows as $row ) {
            $assoc_array = array();
            foreach ( $headers as $index => $header ) {
                $assoc_array = array_merge( $assoc_array, array( $header => $row[ $index ] ) );
            }

            $taxonomy_terms[] = $assoc_array;
        }

        foreach ( $taxonomy_terms as $taxonomy_term ) {
            $taxonomy_term_exists = \term_exists( $taxonomy_term[ $slug ], $custom_taxonomy );
            if ( $taxonomy_term_exists ) {
                continue;
            }

            $term_ids = \wp_insert_term(
                \__( $taxonomy_term[ $taxonomy_term_name ], 'translation_domain' ),
                $custom_taxonomy,
                array(
                    'description' => \__( $taxonomy_term[ $taxonomy_term_description ], 'translation_domain' ),
                    'slug'        => $taxonomy_term[ $slug ],
                    'parent'      => 0
                )
            );

            // Add taxonomy_term meta data if the .csv spreadsheet columns contain
            // additional data.
            // Term meta will be created for all .csv column headers. To avoid duplication
            // of the taxonomy_term_name, taxonomy_term_description, and slug columns,
            // use IF-Statement conditions to skip creating term meta keys for those columns.
            foreach ( $taxonomy_term as $meta_key => $meta_value ) {
                if ( $column_with_newlines == $meta_key ) {
                    $value  = addcslashes( $meta_value, "\n" );

                    // Can save the $value as a single element array
                    // serialized as a JSON-encoded string.
                    // When using get_term_meta, the value must be
                    // JSON-decoded, and the desired data extracted as the
                    // first eleemnt of an array.
                    // For example:
                    // $json_encoded = \get_term_meta( $term_id, $column_with_newlines, $single_value = true );
                    // $json_decoded = json_decode( $json_encoded, $create_assoc_array = true );
                    // $value        = $json_decoded[0];
                    $meta_value = json_encode(
                        array( $value ),
                        ( JSON_HEX_TAG | JSON_HEX_QUOT )
                    );
                }

                // Fourth term "$unique": When true add_term_meta is blocked if key already exists.
                $result = \add_term_meta( $term_ids['term_id'], $meta_key, $meta_value, $unique = true );
                if ( \is_wp_error( $result ) ) {
                    die( 'Import error' );
                    // TODO: taxonomy_terms import add_term_meta WP_Error handling.
                }
            }
        }
    } catch ( \Exception $e ) {
        // TODO: Exception handling if taxonomy_terms import used.
    }
}