Orchard CMS: How to implement custom field indexing? - orchardcms

I have HtmlBlock field and I want to add this field to Orchard CMS index.
Is there some stuff I have to implement to add field in index, like OnIndexing method for custom part indexing described here: https://orchard.codeplex.com/discussions/255183

To enable custom fields indexing you need to describe fields in FieldDriver.
protected override void Describe(DescribeMembersContext context)
{
context
.Member(null, typeof(string), T("HTML"), T("The HTML value of the field."))
.Enumerate<HtmlBlockField>(() => field => new[] { field.HTML });
}

Okay, so after I actually read your question instead of just writing a dumbass comment repeating random words you had written, fields in Orchard automagically get that "include in index" added to them. This is done in the Indexing module in Settings/EditorEvents.cs. It should then go ahead and index your field. Make sure you enable Indexing :)
I did just test it on my super quickly made field and it did appear to work. But I wouldn't say I'm 100% sure ^_^

Related

How to attach Content Parts only to specific Types or specific Content Items?

I have two similar problems that I suspect have a common solution.
1) I'd like to create custom Parts that are Attachable, but only to specific content types, only Taxonomies for example. It would be really cool if that was possible out of the box through migrations e.g something like .Attachable(cfg => cfg.ToType("Taxonomy")) but I don't think it is.
Currently, to prevent my custom Part from being used on content that it's not intended for, I just write checks in the driver methods:
protected override DriverResult Editor(CustomPart part, dynamic shapeHelper)
{
if (part.ContentItem.ContentType != "Taxonomy") return null;
return ContentShape("Parts_Custom_Edit", ...
}
Is this a good way to go about it? Would the Handler be better fit for this kind of logic?
2) Similarly, I'd like to be able to conditionally attach different Parts to different individual Content Items. For example, I would like only first level parent Terms in a Taxonomy to have some fields while child Terms have some others.
The best way I can currently come up with to handle this is to just create one Part that holds all fields and run similar checks to the one above in its Driver methods to return different models depending on its container. Then in the template View I check which fields to render:
#if (Model.ThisField != null) {
<div>#Html.EditorFor(m => m.ThisField)</div>
}
else {
<div>#Html.EditorFor(m => m.ThatField)</div>
}
Ideally I'd like to create one attachable Part that's capable of adding several non-attachable secondary Parts to existing Content Items when it is attached to a Type and to new Content Items when they are created or updated. Is there a painless way to do this? I think 'Welding' might be what I need but I haven't been able to find any documentation or tutorials that can explain Welding to me like I'm five.
I think you need to implement a dynamic welding approach. I had to solve a similar issue, it is posted here. Hope this helps.

Orchard CMS: add image to custom Item

Hi once again :) My next question about Orchard CMS looks trivial but..
I have my custom NewsModule with NewsItem type which consists of TitlePart, BodyPrt, and my custom NewsPart. NewsPart is based on NewsPartRecord.
Now I have to extend my NewsItem document type with Image. So far I found that there are ImagePart and MediaLibraryPickerField.
ImagePart stores width and heihgt of image, so I think it is something for internal use.
The next one is MediaLibraryPickerField. After googling for a while, I found that I can extend my NewsPart using WithField() method.
But! First question here: when I'm configuring Page type with Admin UI, I can add field to the type. But using Migrations I can't add field to NewsItem, only to NewsPart.
The second question here. MediaLibraryPicker allows me to select any type of file from library, image, text, zip or any other. And this is not what I actually need.
So, what are the best practices in Orchard to extend Items with icons?
thanks.
You can add fields to NewsItem, it just requires a different type of definition. It confused me too as it's not as intuitive as you'd like it to be.
To add parts you are using AlterTypeDefinition.
this.ContentDefinitionManager.AlterTypeDefinition(
"NewsItem",
cfg => cfg.WithPart("NewsPart"));
But to add fields you have to also use AlterPartDefinition and specify the NewsItem not the NewsPart.
this.ContentDefinitionManager.AlterPartDefinition(
"NewsItem",
builder =>
builder.WithField(
"NewsImages",
fieldBuilder =>
fieldBuilder.OfType("MediaLibraryPickerField")
.WithDisplayName("News Images")
// Allow multiple images
.WithSetting("MediaLibraryPickerFieldSettings.Multiple", "true"))
Considering second question, MediaLibraryPickerField has option to display only selected types/parts.
.WithSetting(MediaLibraryPickerFieldSettings.DisplayedContentTypes="Document,Video")
If you need new media type you have to create new ContentType with Stereotype "Media", it also needs "MediaPart" and part that defines metadata for that type. You can look at how Document or Video is defined for sample code.

Customized Tridion Search Index Handler: Custom vs Standard field for page url?

I was playing around with custom Search Indexing Handlers for SDL Tridion 2011 (GA). I got something working, using the very helpful information provided by Arjen, however I am not sure if my execution is the best option.
The requirement is to be able to search for pages in the CMS by url (eg www.example.com/news/index.html). In order to do this I have the created a class using the ISearchIndexingHandler interface (code below). I am indexing the url in the ContentText field of the item, however I am not sure if this would normally contain something else for a page (I think a page only has metadata so this should be OK). The advantage of using this over a custom field is that I can simply type the url in the search box without having to use <url> IN <fieldname> or something like that.
So my question is, is there any reason not to use ContentText for Pages, and is there any advantage in using a custom field? Also bonus marks go to anyone with good ideas on how to handle BluePrinting (if I create a page in a parent publication, I want the local urls also to be indexed in the child publications), and the case where a Structure group path is altered (I guess I can somehow trigger a re-index of child page items from within my indexing handler).
The code:
using System;
using Tridion.ContentManager.Search;
using Tridion.ContentManager.Search.Indexing.Handling;
using Tridion.ContentManager.Search.Indexing.Service;
using Tridion.ContentManager.Search.Indexing;
using Tridion.ContentManager.Search.Fields;
namespace ExampleSearchIndexHandler
{
public class PageUrlHandler : ISearchIndexingHandler
{
public void Configure(SearchIndexingHandlerSettings settings)
{
}
public void ExtractIndexFields(IdentifiableObjectData subjectData, Item item, CoreServiceProxy serviceProxy)
{
PageData data = subjectData as PageData;
if (data != null)
{
PublishLocationInfo info = data.LocationInfo as PublishLocationInfo;
string url = GetUrlPrefix(data) + info.PublishLocationUrl;
item.ContentText = url;
}
}
private string GetUrlPrefix(PageData page)
{
//hardcoded for now, but will be read from publication metadata
return "www.example.com";
}
}
}
You can store the url in the ContextText Property. Thies field is used to index Template content data.
Tridion does not index shared item(s) of child publication.
Indexing is triggered on Item modification(create, update, delete, localize and unlocalize).
Or you can use reindexing tool to reindex ur item. but there is no way to index shared items in child publication.
I don't think you can include the URL prefix in neither your search query as the indexed item. Because shared items are not indexed, you will probably index the Page from the Website Structure layer, which is never published.
When a Structure Group is moved you would have to make an event handler that triggers re-indexing all child pages using a protected method of the TOM.NET API. This method is not part of the public API, so posting the code for that solution would probably declare me a persona non grata with R&D :)
Before you re-index anything you should store the original publish location url of the Structure Group in the TcmEventArgs.ContextVariables property, so you can verify whether or not a re-indexing action is necessary.

Hiding a SharePoint Custom Field Type in Edit and Create mode

I am trying to create a Custom Field Type in SharePoint.
This control has it's value set based on another field in the same list.
Because of this requirement, this field should be displayed only in the Display Mode, and not in the Edit or Create mode.
How do I ensure this?
If I just code the ASCX control to not render a field, the field will show up like this in the Edit and Create mode.
alt text http://www.mannsoftware.com/blog/Lists/Photos/121308_0204_CrossSiteLo6.png
Generally you set the SPField.ReadOnlyField property to True to achieve the desired behaviour for any field. (Don't forget to SPField.Update accordingly!) There is an equivalent CAML attribute for list definitions, I believe.
That said, in your control class deriving from BaseFieldControl, you might just override the RenderFieldForInput() method and not call the base implementation to ensure nothing is rendered during Create or Edit. However, this would still render the field's table row in the form, which is probably not what you want. So to enforce the desired behaviour, use ReadOnlyField and override Update() in your SPField (not field control) class to always have it set to True.
It might be easier to just change this on a list-by-list basis by going to the Advanced section of the List Settings, setting Allow management of content types? to Yes, and then editing your content type to change the value of your field to 'hidden'.
Take a look at this blog post. I think it will give you some ideas. The concept uses different rendering templates based on the mode.
http://sharepoint.nailhead.net/2008/04/creating-rendering-template-that.html
Did you try and set the field as hidden?
http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.spfield.hidden.aspx
Custom FORMS pages for new item and edit item (NewForm.aspx and EditForm.aspx) would be another way to achieve this.
Setting the ShowInEditForm and ShowInNewForm properties solved this for me.

How to create a lookup column that targets a Doc Lib and uses the 'Name' of the document?

How do you create a lookup column to a Document Library that uses the 'Name' of the document as the lookup value?
I found a blog post that recommends adding another custom field like "FileName" and then using a item reciever to populate the custom field with the value from the Name field but that seems cheesy.
Link to the blog in case people are interested:
http://blogs.msdn.com/pranab/archive/2008/01/08/sharepoint-2007-moss-wss-issue-with-lookup-column-to-doc-lib-name-field.aspx
I've got a bunch of custom document content types that I dont want to clutter with a work around that should really work anyway.
I created a one step workflow to set the title from the name, fired on modify and created. Seems to work and took seconds to create.
One way you can do this (although not the easiest way) is by creating a custom field type that extends the SPFieldLookup class. SharePoint's field editor for Lookup fields purposefully hides any columns types that aren't supported by Lookup fields, but you can create a field editor for your custom field type that shows them.
However, I have created a Lookup column that points to a Name column in a Document Library before, and it probably doesn't work like you'd expect. While the value stored in the lookup column is valid, it doesn't show up right in List view or on the View Properties form.
The solution you posted may actually be the best way to handle this. Lookup fields require some kludges if you want to handle more complex scenarios, but that's because they're not meant to provide the same functionality as a foreign key relationship in a database.
Coding in any form always scares me. So Here's what I did: I simply renamed the Stupid "Title" Field to something else, say "Keywords", since you cant do anything with that field: cant even make it mandatory.
Then I created another Single line field called "Title" and used this field for the Lookups
Well there is a simple solution to that and in might work in some case.
In the nutshell if you make the Title field Mandatory, this will force the user to enter a title. In that manner we can use title field as a lookup field.
Now How to do that?
One you are done create a document library go to the library setting. Select Advance Setting and Select Yes for the option "Allow management of content types?".
Then go back to the Library setting and Under content types select the "Document" Content type. THen Select Title Column and then Select "Required (Must contain information)" and say OK.
Now try uploading a document to this document library. You will see Title field in the form.
Hope this helps
Cheers
Vaqar
You have to add the field as XML with the ShowField as 'FileLeafRef'
var XmlFieldDefinition = "<Field DisplayName='myLookupColumn' Type='LookupMulti' StaticName='myLookupColumn' Name='myLookupColumn' Required='FALSE' List='THE LOOKUP ID HERE' WebId='THE WEB ID HERE' UnlimitedLengthInDocumentLibrary='TRUE' Mult='TRUE' Sortable='FALSE' ShowField='FileLeafRef' />"
Field fld = fieldCollection.AddFieldAsXml(XmlFieldDefinition, true, AddFieldOptions.DefaultValue);
ClientContext.Load(fld);
ClientContext.ExecuteQuery();

Resources