Le Giang
Apr 2, 2018
visibility 4161
star star star star star
(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

error Please login to comment.
Latest blogs
The Silent Success: When Your Optimizely SaaS CMS Config Push Succeeds with "0" Changes

  Picture this frustratingly common scenario in headless, code-first development with Optimizely SaaS CMS: You’ve defined a brilliant new element,...

Vipin Banka | Jul 13, 2026

Architecting an Enterprise-Grade Development Pipeline in Optimizely SaaS CMS

Most enterprise teams show up to Optimizely SaaS CMS with a clear roadmap for their release pipeline: DEV → QA → Stage → Prod. Four logical...

Vipin Banka | Jul 12, 2026

Bynder DAM Connector for Optimizely SaaS CMS: Improved Metadata Property Synchronization

While working with the Bynder DAM Connector for Optimizely SaaS CMS , one of the key areas I explored was how Bynder asset metadata is synchronized...

Vipin Banka | Jul 11, 2026

Optimizely DXP: Every Supported Culture, One Searchable Page

Quick one for anyone building multi-language sites on Optimizely DXP. I put together a reference tool listing all 806 supported cultures. More...

Adnan Zameer | Jul 10, 2026 |