Ask your WordPress questions! Pay money and get answers fast! Comodo Trusted Site Seal
Official PayPal Seal

Strip hyphens in post titles from post slugs WordPress


I'm doing several massive migrations from an old platform that treats hyphens and periods in post titles differently from WordPress. The differences will cause hundreds of 404s for an otherwise completely matching permalink structure between the two platforms.

Normally WordPress replaces a period in a post title with a hyphen in the sanitized title used in the post slug. I needed it to be replaced with nothing and was able to do this with the function below.

But I also need hyphens used in post titles to be removed and keep on botching it by instead removing all hyphens from the slug.

An example of what I'm looking for:

Post title: This is a hyphen-happy post title!
Normal WordPress slug would be: this-is-a-hyphen-happy-post-title
What I need the WordPress slug to be: this-is-a-hyphenhappy-post-title

Here is my function as it stands:

remove_filter('sanitize_title', 'sanitize_title_with_dashes');

function jpl_migration_sanitize_title_with_dashes($title, $raw_title = '', $context = 'display') {
$title = strip_tags($title);
// Preserve escaped octets.
$title = preg_replace('|%([a-fA-F0-9][a-fA-F0-9])|', '---$1---', $title);
// Remove percent signs that are not part of an octet.
$title = str_replace('%', '', $title);
// Restore octets.
$title = preg_replace('|---([a-fA-F0-9][a-fA-F0-9])---|', '%$1', $title);

if (seems_utf8($title)) {
if (function_exists('mb_strtolower')) {
$title = mb_strtolower($title, 'UTF-8');
$title = utf8_uri_encode($title, 200);

$title = strtolower($title);
$title = preg_replace('/&.-+?;/', '', $title); // kill entities
$title = str_replace('.', '', $title); // removed hyphen replacement for periods

if ( 'save' == $context ) {
// Convert nbsp, ndash and mdash to hyphens
$title = str_replace( array( '%c2%a0', '%e2%80%93', '%e2%80%94' ), '-', $title );

// Strip these characters entirely
$title = str_replace( array(
// iexcl and iquest
'%c2%a1', '%c2%bf',
// angle quotes
'%c2%ab', '%c2%bb', '%e2%80%b9', '%e2%80%ba',
// curly quotes
'%e2%80%98', '%e2%80%99', '%e2%80%9c', '%e2%80%9d',
'%e2%80%9a', '%e2%80%9b', '%e2%80%9e', '%e2%80%9f',
// copy, reg, deg, hellip and trade
'%c2%a9', '%c2%ae', '%c2%b0', '%e2%80%a6', '%e2%84%a2',
), '', $title );

// Convert times to x
$title = str_replace( '%c3%97', 'x', $title );

$title = preg_replace('/[^%a-z0-9 _-]/', '', $title);
$title = preg_replace('/\s+/', '-', $title);
$title = preg_replace('|-+|', '-', $title);
$title = trim($title, '-');

return $title;

add_filter('sanitize_title', 'jpl_migration_sanitize_title_with_dashes');

Answers (1)


Dbranes answers:

if you are using the function "wp_insert_post" to import the data, you could try something like:

function custom_slug( $data , $postarr ){
return $data;

add_filter( 'wp_insert_post_data' , 'custom_slug' , 99);

i.e. remove the "-" from the post title before sanitizing it.

Hope this helps

Dbranes comments:

I have tested the above filter with:

// Create post object
$my_post = array(
'post_title' => 'This is a hyphen-happy post title!',
'post_content' => 'This is my post.',
'post_status' => 'publish',

// Insert the post into the database
wp_insert_post( $my_post );

and it gives the correct post_name: <strong>this-is-a-hyphenhappy-post-title</strong>

I have also tested this via WordPress eXtended RSS (WXR) file import with an item like this:

<title>This is a hyphen-happy post title!</title>

and it is imported into a post with the correct post_name: <strong>this-is-a-hyphenhappy-post-title</strong>

The Wordpress import is also using the wp_insert_post function.

How are you importing your data?

joshualynch comments:

I will be using the Movable Type and TypePad tool to import the data. Using the WXR import, this works exactly as I need!

However, I am getting a PHP Warning: Missing argument 2 for this line when I try to do things like delete posts:

function custom_slug( $data , $postarr ){

Dbranes comments:

Do you get the warning if you use

function custom_slug( $data){


joshualynch comments:

That did the trick, thanks!