Solving Random Disappearing of Toolset Types Custom Taxonomy

This blog post is for those experiencing their Toolset Types’s custom taxonomy disappearing randomly.  The symptom of the disappearance is that when you go to Toolset > Taxonomies and ALL of your custom taxonomies are gone.  Also any taxonomies tied to a post type is now disassociated so when you try to go add a new post type that has an associated taxonomy, you no longer see the taxonomy options you’ve created for that post.  The only taxonomies you see are the default WordPress ones which is Categories and Tags.

I have yet unable to track down the source of the bug as it occurs in our environment randomly.  We’ve tried flushing out the transient keys, updated everything to the latest and greatest, debugging the data in the database, and isolating the plugin. Do note that this might be a niche issue involving our unique environment which is as follows:

  • Project Nami WordPress 1.7.1 (equivalent to WordPress 4.9.1)
  • Toolset Types 2.2.21

Here’s what I’ve found and the workaround used.  

Toolset Types stores all the custom taxonomy you’ve made with the plugin as a serialized array in the wp_options table.  The easiest way to find which data row has the Toolset data is to recreated the missing custom taxonomies, if you haven’t already.  Then in one of the description of one of the custom taxonomy, add a unique keyword, keeping note of the letter casing.  Here’s my example:

Now we can go into the database and query for that exact keyword to find the record in the database.  The query should be something like the following, with the exception that you will replace my keyword and wp_option table prefix with yours:

select * from wp_options where option_value = 'xXSarnXx'

If that doesn’t work, you can try doing this (although I prefer to do the top for reasons later in this post).

select * from wp_options where option_name = 'wpcf-custom-taxonomies'

You’ll then find the record that Toolset Types uses.  You should only see 1 record.  Keep in mind of the option_value and option_id columns.  You’ll need to use that later.

In option_value, you’ll see data that beings with something like this:

a:4:{s:8:"category";a:25:{s:4:"name";s:8:"category";s:5:"label";s:10:"Categories";s:6:"labels";a:21:{s:4:"name";s:10:"Categories";s:13:"singular_name";s:8:"Category";s:12:"search_items";s:17:"Search Categories";s:13:"popular_items";N;s:9:"all_items";s:14:"All Categories";s:11:"parent_item";s:15:"Parent Category";s:17:"parent_item_colon";s:16:"Parent Category:";s:9:"edit_item";s:13:"Edit Category";s:9:"view_item";s:13:"View Category";s:11:"update_item";s:15:"Update Category";s:12:"add_new_item";s:16:"Add New Category";s:13:"new_item_name";s:17:"New Category Name";s:26:"separate_items_with_commas";N;s:19:"add_or_remove_items";N;s:21:"choose_from_most_used"; .....

That’s the serialized data that Toolset Types stores it’s data like the custom taxonomies.  If you’re interested in unminifying the data to study it, I recommend http://www.unserialize.com/.  You can dump your serialized array in there to see where your custom taxonomies are stored in that data.  It may be a benefit to get familiar with the serialized data for the upcoming steps.  Do note that your serialized array should be much larger than this default example:

This is where the band-aid comes into play.  Now that you’ve just re-created the custom taxonomy and found the row that Toolset Types stores it’s data.  You now have the value you’ll want to keep in place under option_value and the id in option_id.  What the band-aid involves is creating a cron that will re-insert the serialized array (that has our settings) in option_value.  What happens is that the data in this column some how gets reset.  I’m not sure what causes it.  I do know that if the serialize array gets corrupted, Toolset Types will resets the serialized array.  So perhaps something is causing a corruption of the serialize array.  In any case, I have a cron that runs daily to just re-insert the serialize array back into the row, before our cache engine caches the site.  If you don’t have a caching engine.  You may want to run a cron more often, perhaps hourly to minimize downtime of when the taxonomies are missing.

Here is a snippet of the script for the cron I use.    A couple key notes:

  • The reason why I used the “backdoor keyword” like ‘xXSarnXx’ is so that I can find and replace the keyword with a timestamp of when the cron ran and see it in the description of all the custom taxonomies so its obvious that the cron ran and also for future maintenance so future developers know that there is a band-aid going on.
  • You will need to parse out the serialize array that you want to insert into the option_values column.  All quotes will need to be prefixed with a backslash.
  • You’ll need to adjust the database object to what you’re using.
  • You’ll want to password protect your cron (the coding to do this is not shown here).
  • Below you’ll see a variable called $desc where I put a timestamp and a trigger keyword.  This allows me and future developers know that there is something “more” going on and to investigate further. It also allows me to quickly check is the cron gets triggered as you can see from the screenshot after the code snippet below.

$start = date("F j, Y, g:i a");
ini_set('max_execution_time', 0); //45 mins (60 * 45)
set_time_limit(0);

$desc = "WP-Cron-Fixes-" . $start .'-xXSarnXx';
// re-insert custom-tax
$sql = "
update [ms].[wp_options]
set
option_value = 'a:4:{s:8:\"category\";a:25:{s:4:\"name\";s:8:\"category\";s:5:\"label\";s:10:\"Categories\";s:6:\"labels\";a:21:{s:4:\"name\";s:10:\"Categories\";s:13:\"singular_name\";s:8:\"Category\";s:12:\"search_items\";s:17:\"Search Categories\";

... MORE SERIALIZED DATA CUT ...

%s\";s:9:\"menu_name\";s:2:\"%s\";}s:4:\"slug\";s:14:\"story-category\";s:11:\"description\";s:".strlen($desc).":\"".$desc."\";s:6:\"public\";s:6:\"public\";s:12:\"hierarchical\";s:12:\"hierarchical\";

... MORE SERIALIZED DATA CUT ...

;s:9:\"menu_name\";s:2:\"%s\";}s:4:\"slug\";s:5:\"pages\";s:11:\"description\";s:".strlen($desc).":\"".$desc."\";s:6:\"public\";s:6:\"public\";s:12:\"hierarchical\";s:12:\"hierarchical\";

... MORE SERIALIZED DATA CUT ...
";

AND..there you have it!  So with this band-aid, whenever you go and view your custom taxonomy within Toolset Types, you’ll see something like this which will show you when the last cron ran to patch back in the Toolset Types data.