Use one instance of Content Part for every object it's attached

Topics: Writing modules
Oct 23, 2012 at 12:58 PM

Hi! Could you please explain how to do it? I'm writing a module that displays social networks' buttons for blog posts. There should be only one record in table that contains script. I made it like this:

	[UsedImplicitly]
	public class SocialPartHandler : ContentHandler
	{
		public Localizer T { get; set; }

		public SocialPartHandler(IRepository<SocialRecord> repository)
		{
			T = NullLocalizer.Instance;
			Filters.Add(new ActivatingFilter<SocialPart>("Site"));
			Filters.Add(StorageFilter.For(repository));
		}

        protected override void GetItemMetadata(GetContentItemMetadataContext context)
        {
            if (context.ContentItem.ContentType != "Site")
                return;
            base.GetItemMetadata(context);
			context.Metadata.EditorGroupInfo.Add(new GroupInfo(T("Social buttons")));
        }
	}

Then I've added Social part to Blog post ang got a surprise: blog post don't want to use that one global record, it tries to convert itself As<Social> and receives null data. How to do this in a right way?

Developer
Oct 23, 2012 at 3:50 PM

Have you added a Driver with a Display method?

Oct 24, 2012 at 3:49 AM
Edited Oct 24, 2012 at 3:49 AM

Yes, sure. Everything is quite the same as for sample Maps part: http://docs.orchardproject.net/Documentation/Writing-a-content-part , even easier: just one string field for script in model.

The trick is that Maps uses different instance for every content it attached to, but my module should use only one record everywhere.

Oct 24, 2012 at 5:16 AM

Finally I've implemented this as HTML widget. But question remains: is it possible to have "singleton" content part or, in other words, share data record between each instance.

Developer
Oct 25, 2012 at 10:04 AM

That's not how content parts are designed. What you could do instead, is create a SocialSettingsPart and attach that one to the Site content type. Next, have your SocialPart query the Site content by casting it to a SocialSettingsPart. To get a reference to the site content item, use the IOrchardServices.WorkContext.CurrentSite property. Although you can't inject services into content parts via the constructor, you could do it by implementaing the Activated method on your content handler and use property injection. Or even implement a LazyField<T> construct that accesses the current site and your SocialSettingsPart. Checkout the Email module to see how to setup custom site settings.