Access Custom Site Settings in Filters

Topics: Customizing Orchard
Jan 21, 2015 at 6:20 PM
I'm trying to access a custom content part that is set to be part of the Site similar to the email module's http site settings content part. I can access the settings created this way from within a driver using:

var settings = workContext.CurrentSite.As<CustomSettingsPart>();

However if I try to use this method from within a filter the workContext.CurrentSite no longer has an As method with which to grab my custom settings. I have tried using:

var settings = _contentManager.Query<CustomSettingsPart>("CustomSettings").List().FirstOrDefault();

But that throws an error:

System.NullReferenceException: Object reference not set to an instance of an object.

Is there another method I should be using to grab my settings from within a filter.cs file? Thank you.
Jan 21, 2015 at 6:24 PM
I changed my code from:

var settings = _contentManager.Query<CustomSettingsPart>("CustomSettings").List().FirstOrDefault();

to:

var settings = _contentManager.Query<CustomSettingsPart>().List().FirstOrDefault();

and it appears to be working now. Can someone explain why this is and whether or not this is an acceptable way of accomplishing my task? Thank you.
Jan 22, 2015 at 2:35 AM
For this query extension, to limit the results, you can specify one or an array of content types (e.g "OneType") or the version options (e.g VersionOptions.Published). This doesn't work with "CustomSettingsPart" because it's not a content type. Here, the targeted content type is "Site"...

It's not your case, but when "YourPart" is associated with a "YourPartRecord" it's better to use ".Querry<YourPart, YourPartRecord>()..." this because somewhere a join is done that prevents from multiple inner selects...

But you was first right, some data as site settings are availables in an unit of work (e.g web request), so it's not necessary to "Query" them. The use of an IWorkContextAccessor is a right way if you init and use it as in many examples in the source code
private readonly IWorkContextAccessor _workContextAccessor;
...
public YourFilterClass(..., IWorkContextAccessor workContextAccessor) {
....
    _workContextAccessor = workContextAccessor;
}
...
var settings = _workContextAccessor.GetContext().CurrentSite.As<CustomSettingsPart>(); 
In the same way, you can also inject an "ISiteService" and then use this
_siteService.GetSiteSettings().As<CustomSettingsPart>()

Regards
Marked as answer by emeraldarcher on 2/2/2015 at 11:15 AM
Jan 24, 2015 at 9:40 AM
The method .As is an extension method. Did you import Orchard.ContentManagement in your Filter?
using Orchard.ContentManagement;
On a side note, this is a great article on using custom site settings, especially from 1.8 this has become incredibly easy:

http://docs.orchardproject.net/Documentation/Adding-custom-settings
Marked as answer by emeraldarcher on 2/2/2015 at 11:15 AM
Feb 2, 2015 at 4:54 PM
What if you would like settings to be accessible through the Admin Menu to users who do not have permission to change site settings? So instead of placing it under the Settings drop-down menu you could place it with the rest of the Admin Menu as its own area.
Feb 3, 2015 at 4:31 PM
For the best control over placement in the Admin navigation and permissions, you can look at implementing your own Orchard.Security.Permissions.IPermissionProvider in combination with implementing your own Orchard.UI.Navigation.INavigationProvider - there are many examples in the core modules, look at for example Orchard.Blogs which implements an "AdminMenu" class and a "Permissions" class.

You can implement those interfaces either at module level or at feature level when used with the OrchardFeature attribute.
Feb 3, 2015 at 5:19 PM
Edited Feb 3, 2015 at 6:18 PM
This would work but then I would have to create an AdminController and a migrations and set up my settings to no longer be tied into the site settings. I'm guessing this will have to be otherwise they wouldn't be able to access it anyways since they don't have permissions to access site settings.

Is there a way I could instead alter the permissions so an admin without full site settings permissions could still access just the speedbump settings?

Edit: I tried creating an AdminController that will return the same .cshtml file my site settings returned but there isn't a way to save any changes made, as it just displays the contents of the .cshtml file. What I'm trying to accomplish makes most sense as a site setting but I need users without the permission to edit site settings to be able to edit this. I don't want it to create a new content item every time a change is made like in the blogs module or tekno.flexslider.
Feb 3, 2015 at 6:54 PM
Edited Feb 4, 2015 at 8:28 PM
I may run into more instances where I want to achieve something along these lines. Would it be possible to create a content item like SiteExtended which will act exactly like the Site content item and be able to attach various site settings to it that require permissions other than site settings? I've been trying to find where this Site content item is set up and how it accomplishes this, but haven't really figured anything out yet. Thank you.

Edit: I found where the Settings menu was being built and copied it to my own module and have it all set up to work. Now I just have to associate this menu with my ExtendedSite content item instead of the Site content item (it currently is displaying the same settings parts as the standard Settings menu). I imagine this would have something to do with the following code in the AdminMenu.cs file:
var site = _siteService.GetSiteSettings();
            if (site == null)
                return;

            foreach (var groupInfo in Services.ContentManager.GetEditorGroupInfos(site.ContentItem)) {
                GroupInfo info = groupInfo;
                builder.Add(T("Extended Settings"),
                    menu => menu.Add(info.Name, info.Position, item => item.Action("Index", "Admin", new { area = "Orchard.ExtendedSettings", groupInfoId = info.Id })
                        .Permission(Permissions.ManageExtendedSettings)));
            }
The list is being built by grabbing the site settings from the ISiteService interface and selecting it's content item which will let you sift through each part which has been added to the Site content item. How would I go about switching this to work with my ExtendedSite content item instead of the Site content item? Will I need to create a new ISiteService and ISite interface as seen in Orchard.Settings? How would I then tie my ExtendedSettings content item to my new interfaces and tie in parts that should be associated with ExtendedSettings? Thank you.