Take the community feedback survey now.

Le Giang
Apr 2, 2018
  3829
(2 votes)

Implement search provider for pages, blocks and media

Currently when I type to search in navigationtree, surprisingly there is no result returned even for pages, block or media. It seems that someone forgot to implement searching feature or it is being underplayed smile.

In this post, I would like show you how to implement a search provider for pages, blocks and media and you can customize to fit your need.

For pages:

[SearchProvider]
    public class DefaultPageSearchProvider : ContentSearchProviderBase<IContent, ContentType>
    {
        public DefaultPageSearchProvider(LocalizationService localizationService, ISiteDefinitionResolver siteDefinitionResolver, IContentTypeRepository<ContentType> contentTypeRepository, EditUrlResolver editUrlResolver, ServiceAccessor<SiteDefinition> currentSiteDefinition, LanguageResolver languageResolver, UrlResolver urlResolver, TemplateResolver templateResolver, UIDescriptorRegistry uiDescriptorRegistry) : base(localizationService, siteDefinitionResolver, contentTypeRepository, editUrlResolver, currentSiteDefinition, languageResolver, urlResolver, templateResolver, uiDescriptorRegistry)
        {

        }

        /// <summary>
        ///
        /// </summary>
        public override string Area
        {
            get
            {
                return "cms/pages";
            }
        }

        /// <summary>
        ///
        /// </summary>
        public override string Category
        {
            get
            {
                return "pages";
            }
        }

        protected override string IconCssClass
        {
            get
            {
                return "epi-iconObjectPage";
            }
        }

        public override IEnumerable<SearchResult> Search(Query query)
        {
            var contentRepository = ServiceLocator.Current.GetInstance<IContentRepository>();
            var pageQueryService = ServiceLocator.Current.GetInstance<IPageCriteriaQueryable>();
            PropertyCriteriaCollection crits = new PropertyCriteriaCollection();

            PropertyCriteria nameCriteria = new PropertyCriteria();
            nameCriteria.Name = MetaDataProperties.PageName;
            nameCriteria.Value = query.SearchQuery;
            nameCriteria.Type = PropertyDataType.String;
            nameCriteria.Required = true;
            nameCriteria.Condition = CompareCondition.Contained;

            crits.Add(nameCriteria);
            //Add criteria so search is performed against all providers
            crits.Add(new PropertyCriteria
            {
                Name = "EPI:MultipleSearch",
                Value = "*"
            });

            PageDataCollection pages = null;
            try
            {
                pages = pageQueryService.FindAllPagesWithCriteria(ContentReference.RootPage, crits, null, LanguageSelector.MasterLanguage());
            }
            catch (NotImplementedException)
            {
                // If the provider hasn't implemented FindAllPagesWithCriteria, call old FindPagesWithCriteria instead.
                pages = pageQueryService.FindPagesWithCriteria(ContentReference.RootPage, crits, null, LanguageSelector.MasterLanguage());
            }
            return pages.Select(CreateSearchResult);
        }
    }

For blocks

 [SearchProvider]
    public class DefaultBlockSearchProvider : ContentSearchProviderBase<IContent, ContentType>
    {
        public DefaultBlockSearchProvider(LocalizationService localizationService, ISiteDefinitionResolver siteDefinitionResolver, IContentTypeRepository<ContentType> contentTypeRepository, EditUrlResolver editUrlResolver, ServiceAccessor<SiteDefinition> currentSiteDefinition, LanguageResolver languageResolver, UrlResolver urlResolver, TemplateResolver templateResolver, UIDescriptorRegistry uiDescriptorRegistry) : base(localizationService, siteDefinitionResolver, contentTypeRepository, editUrlResolver, currentSiteDefinition, languageResolver, urlResolver, templateResolver, uiDescriptorRegistry)
        {

        }

        /// <summary>
        ///
        /// </summary>
        public override string Area
        {
            get
            {
                return "cms/blocks";
            }
        }

        /// <summary>
        ///
        /// </summary>
        public override string Category
        {
            get
            {
                return "blocks";
            }
        }

        protected override string IconCssClass
        {
            get
            {
                return "epi-objectIcon";
            }
        }

        public override IEnumerable<SearchResult> Search(Query query)
        {
            ContentReference root = null;
            if (query.SearchRoots != null && query.SearchRoots.Count() > 0)
            {
                root = new ContentReference(query.SearchRoots.First());
            }
            else
            {
                root = new ContentReference();
            }

            var contentRepository = ServiceLocator.Current.GetInstance<IContentRepository>();
            var contentTypeRepository = ServiceLocator.Current.GetInstance<IContentTypeRepository>();
            var contentProviderManager = ServiceLocator.Current.GetInstance<IContentProviderManager>();
            var blockTypes = contentTypeRepository.List().Where(x => typeof(BlockData).IsAssignableFrom(x.ModelType));
            var provider = contentProviderManager.GetProvider(root);

            if (provider != null && provider.HasCapability(ContentProviderCapabilities.Search))
            {
                List<IContent> blocks = new List<IContent>();
                foreach(var blockType in blockTypes)
                {
                    blocks.AddRange(provider.ListContentOfContentType(blockType).Where(x => x.Name.IndexOf(query.SearchQuery, StringComparison.InvariantCultureIgnoreCase) >= 0).Select(x => contentRepository.Get<IContent>(x.ContentLink)));
                }

                return blocks.Select(CreateSearchResult);
            }

            return Enumerable.Empty<SearchResult>();
        }
    }

For media:

[SearchProvider]
    public class DefaultMediaSearchProvider : ContentSearchProviderBase<IContent, ContentType>
    {
        public DefaultMediaSearchProvider(LocalizationService localizationService,
            ISiteDefinitionResolver siteDefinitionResolver,
            IContentTypeRepository<ContentType> contentTypeRepository,
            EditUrlResolver editUrlResolver,
            ServiceAccessor<SiteDefinition> currentSiteDefinition,
            LanguageResolver languageResolver,
            UrlResolver urlResolver,
            TemplateResolver templateResolver,
            UIDescriptorRegistry uiDescriptorRegistry) : base(localizationService,
                siteDefinitionResolver,
                contentTypeRepository,
                editUrlResolver,
                currentSiteDefinition,
                languageResolver,
                urlResolver,
                templateResolver,
                uiDescriptorRegistry)
        {

        }

        /// <summary>
        ///
        /// </summary>
        public override string Area
        {
            get
            {
                return "CMS/files";
            }
        }

        /// <summary>
        ///
        /// </summary>
        public override string Category
        {
            get
            {
                return "media";
            }
        }

        protected override string IconCssClass
        {
            get
            {
                return "";
            }
        }

        public override IEnumerable<SearchResult> Search(Query query)
        {
            ContentReference root = null;
            if (query.SearchRoots != null && query.SearchRoots.Count() > 0)
            {
                root = new ContentReference(query.SearchRoots.First());
            }
            else
            {
                root = new ContentReference();
            }

            var contentRepository = ServiceLocator.Current.GetInstance<IContentRepository>();
            var contentTypeRepository = ServiceLocator.Current.GetInstance<IContentTypeRepository>();
            var contentProviderManager = ServiceLocator.Current.GetInstance<IContentProviderManager>();
            var mediaTypes = contentTypeRepository.List().Where(x => typeof(MediaData).IsAssignableFrom(x.ModelType));
            var provider = contentProviderManager.GetProvider(root);

            if (provider != null && provider.HasCapability(ContentProviderCapabilities.Search))
            {
                List<IContent> mediaList = new List<IContent>();
                foreach (var blockType in mediaTypes)
                {
                    mediaList.AddRange(provider.ListContentOfContentType(blockType).Where(x => x.Name.IndexOf(query.SearchQuery, StringComparison.InvariantCultureIgnoreCase) >= 0).Select(x => contentRepository.Get<IContent>(x.ContentLink)));
                }

                return mediaList.Select(CreateSearchResult);
            }

            return Enumerable.Empty<SearchResult>();
        }
    }

After adding these search providers, now I can enjoy the filtering feature. You can customize the code to fit your need and improve the performance (for example: implement caching mechanism).

Apr 02, 2018

Comments

Please login to comment.
Latest blogs
Optimizely SaaS CMS Developer Certification

I have recently passed the Optimizely SaaS CMS Developer Certification. Sharing my experience, hope this helps. https://academy.optimizely.com/stud...

Madhu | Sep 22, 2025 |

Get last run of a scheduled job in Optimizely CMS

Learn how to get the last execution time of a scheduled job in Optimizely CMS.

Tomas Hensrud Gulla | Sep 20, 2025 |

Replacement Language Settings

Hi, Today I would like to share my learnings about the Replacement Language option in Optimizely CMS and Commerce. Replacement language is used to...

Harinarayanan | Sep 20, 2025

Locating Blocks Stored in “For This Page” When Retiring Block Models

When maintaining a long-lived Optimizely CMS site, you’ll eventually need to deprecate block types. The usual approach is to remove the block class...

Pär Wissmark | Sep 19, 2025 |