I want to add all posts with keyword “Dog Training” in the post title to a specific category.
Reason: If you enter something into WordPress search it’s not an exact match. Previous WordPress search was much more accurate but they gimped it now. Note the space between the words.
You have to check the existing terms first with wp_get_object_terms()
and if the term you need is missing, add it with wp_set_object_terms()
.
It is faster to update the terms just once than to do this for every term.
The following example is running on save_post
. I put everything into a class (and into a plugin) to make the code more readable. You could use just one function tough.
To keep things flexible I implemented three matching algorithms: exact, case-insensitive and regular expression (regex).
The terms must exist already. I choose this requirement to prevent accidental mismatches.
<?php # -*- coding: utf-8 -*-
/**
* Plugin Name: T5 Term by title
*/
add_action( 'save_post', array ( 'WPSE_39700_Term_By_Title', 'init' ), 10, 2 );
class WPSE_39700_Term_By_Title
{
/**
* Post types to process.
*
* @var array
*/
protected $post_types = array ( 'post', 'page' );
/**
* What to search for? Adjust this to your needs.
*
* @var array
*/
protected $searches = array (
'Dog Training' => array ( // string to search for
'search_type' => 'exact', // 'exact', 'case-insensitive' or 'regex'
'taxonomy' => 'category', // existing taxonomy
'term' => 'Dog Training' // existing term name
),
'~\d\s*(kg|kilogram)~i' => array ( // '43kg' or '3 kilogram'
'search_type' => 'regex',
'taxonomy' => 'post_tag',
'term' => 'Health'
),
'wordpress' => array (
'search_type' => 'case-insensitive',
'taxonomy' => 'post_tag',
'term' => 'WordPress'
)
);
/**
* Current post object.
*
* @var object
*/
protected $post = NULL;
/**
* Terms to update.
*
* @var array
*/
protected $update = array ();
/**
* Initial callback function.
*
* @wp-hook save_post
* @param int $post_id
* @param object $post
* @return void
*/
public function init( $post_id, $post )
{
new self( $post_id, $post );
}
/**
* Constructor called by init.
*
* @param int $post_id
* @param object $post
*/
public function __construct( $post_id, $post )
{
// wrong post type
if ( ! in_array( $post->post_type, $this->post_types )
// no title
or '' === trim( $post->post_title )
)
{
return; // Nothing to do.
}
$this->post = $post;
foreach ( $this->searches as $search => $properties )
{
if ( $this->has_match( $search, $properties['search_type'] ) )
{
$this->add_term( $properties['term'], $properties['taxonomy'] );
}
}
$this->write_terms();
}
/**
* Does the title contain our search phrase?
*
* @param string $search
* @param array $type
* @return bool
*/
protected function has_match( $search, $type )
{
switch ( $type )
{
case 'case-insensitive':
// It may return 0, but that's not the same as FALSE.
return FALSE !== stripos( $this->post->post_title, $search );
case 'regex':
return preg_match( $search, $this->post->post_title, $m );
default:
return FALSE !== strpos( $this->post->post_title, $search );
}
}
/**
* Adds the term to the post.
*
* @param string $term
* @param string $taxonomy
* @return void
*/
protected function add_term( $term, $taxonomy )
{
if ( empty ( $this->update[ $taxonomy ] ) )
{
$this->update[ $taxonomy ] = wp_get_object_terms(
$this->post->ID,
$taxonomy,
array ( 'fields' => 'name' )
);
}
if ( get_term_by( 'name', $term, $taxonomy ) )
{
$this->update[ $taxonomy ][] = $term;
$this->update[ $taxonomy ] = array_unique( $this->update[ $taxonomy ] );
}
}
/**
* Takes all terms from $update and relates them to the current post.
*
* @return void
*/
protected function write_terms()
{
if ( ! empty ( $this->update ) )
{
foreach ( $this->update as $taxonomy => $terms )
{
wp_set_object_terms( $this->post->ID, $terms, $taxonomy );
}
}
}
}
Here I have written a post with the title a test with wORdpReSs and 22kg Dog Training and then I hit Save Draft once:

To update existing posts run something like the following once:
$posts = get_posts( array ( 'numberposts' => - 1 ) );
foreach ( $posts as $post )
{
new WPSE_39700_Term_By_Title( $post->ID, $post );
}