Recently I stumped upon this question Removing a property that no longer exists in the code (optimizely.com) . it’s a valid (and even good) question. It is easy to add a new property to your catalog content type – you can simply add a new property to the model, build and start the site. However the opposite is not easy. In Commerce 14 at least.
A property for the strongly typed content type, is actually mapped and backed by a MetaField
in MetaDataPlus system (of course unless you specifically tell it not to, by using IgnoreMetaDataPlusSynchronization
attribute). When you add a new property to your content type, build and start your site, your content type is scanned and metafields will be created if necessary. However, if you delete a property from your content type, the scanner will just leave the metafield there. There are a few reasons for that. Firstly, it allows loosely typed content type, i.e. content types with none, or only a few property defined. If you have used some kind of external PIM, you’ll understand why it is important. Lastly, because the property can be mapped with a metafield of different name, the scanner might have trouble figuring out which metafield to delete. All in all, keeping the metafields is the sensible (if not the right) choice.
Then what to do if you want to delete the property and also clean up the metafield? With Commerce 13 and earlier, you can detach a MetaField
from its MetaClass
(s), then delete it using Commerce Manager. With the dead of CM in Commerce 13, what is your option?
By using code, of course. There are a few APIs – namely MetaField
and MetaClass
that can be used for that purpose. Note that there are two MetaField
and MetaClass
, and only the ones in Mediachase.MetaDataPlus.Configurator
namespace are what we want (the others are for Business Foundation)
Enough for chit chat, this is the code that you would need to run
private void DeleteMetaField(string metafieldName)
{
var metaField = MetaField.Load(CatalogContext.MetaDataContext, metafieldName);
if (metaField == null)
{
return;
}
foreach (int metaClassId in metaField.OwnerMetaClassIdList)
{
var metaClass = MetaClass.Load(CatalogContext.MetaDataContext, metaClassId);
if (metaClass == null)
{
metaClass.DeleteField(metafieldName);
}
}
MetaField.Delete(CatalogContext.MetaDataContext, metaField.Id);
}
It is pretty straightforward. We load the MetaField
by its name, if it is not null, then we remove it from all MetaClass
that are using it, then eventually delete it.
In beginning of this post we mentioned strongly typed content type, but note that order system also uses the same metaclass/metafield system, so this code can be used for them as well.
This piece of code can be used in an admin-privilege controller to delete metafields on demand. Until Commerce 14 allows you to do it with a proper UI.
is MetaFieldName only unique in the scope of the MetaClass?
If so will this code snippet unintendedly delete more than one MetaField across other MetaClass(s)?
No it has to be unique in the entire system. However if you want to be safe (or rather a peace of mind), you can pass in the metaclass id and only delete from there
Thank you for the write up. When I run the code – which I have placed in a scheduled job – it does delete the field in the database, but the editors are still able to see the field in the Commerce UI. After restart, the fields are no longer visible.
Do you know, if there is a way to update the UI – without restarting the UI?
It should do it automatically. Is it the same instance where you run the code and check for UI?