Skip to content

Migrating from non hashed to hashed CPT names

nikolov-tmw edited this page Apr 26, 2013 · 4 revisions

Until commit 014c3e16c1baedadb66a997674ce243cfa6156aa every translation post was stored within a Custom Post Type(CPT) that had an auto-generated name like this:

{%prefix%}{%post_type%}_{%language%}

Where:

  • {%prefix%} was mlwp_
  • {%post_type%} was the name of the original post type(for instance "post")
  • {%language%} was the two-letter language ID(for instance "en")

That worked perfectly for my testing purposes, but I totally overlooked the fact that the post_type column in the posts table is limited to 20 characters - generally that should work for most post types, but there is the chance that it will be unpredictable if the length of the generated post name exceeds 20 characters.

In order to get over that limitation, I decided to use SHA1 and trim the hash to 20 characters - the chances of collision are extremely low(not to say maybe impossible in a WordPress environment). This way I will always get a 20 character post type name.

The method for generating the initial string that is then hashed remains the same(as shown above). Hashing is now handled by the Multilingual_WP::hash_pt_name() method - it stores a static variable with all converted hashes - I know that SHA1 is fast, but this will help you greatly when updating your DB.

How to migrate

Back-up your database!

First of all, make sure to back-up your DB, using phpMyAdmin, a backup plugin for WordPress, or however you want. Even though the migration solution is really simple and nothing should go wrong in theory, it's always good to have a back-up before doing things with your DB.

Edit the plugin.php file

Open the plugin.php file in an editor of your choice and find the line that says

public function hash_pt_name( $pt, $lang = false ) {

Then, change the following code:

	if ( ! isset( $hashed_names[ $id ] ) ) {
		$hashed_names[ $id ] = substr( sha1( $id ), 0, 20 );
	}

To this code:

	if ( ! isset( $hashed_names[ $id ] ) ) {
		$hashed_names[ $id ] = substr( sha1( $id ), 0, 20 );
		global $wpdb;
		var_dump( $wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->posts} SET `post_type` = %s WHERE `post_type` = %s", $hashed_names[ $id ], $id ) ) );
	}

Now go to your site/refresh it. At the top of the page, you should see an output similar to this:

int(74) int(74) int(74) int(74) int(524) int(524) int(524) int(524) 

This is the amount of modified rows during the query that we did above(with the $wpdb->query() function). This should generally correspond to the number of languages and posts/pages/custom-post-types that you have in your site. In this case I had 4 enabled languages, 74 posts and 524 pages.

That's all!

That's pretty much the technique I used to migrate my test site(well I actually used a much more complicated and awkward method, since I didn't think about using the $wpdb class :) ) and everything seems to be holding up for now.