Le Giang
Apr 2, 2018
  3985
(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 PaaS + Figma + AI: Auto‑Generate Blocks with Cursor

What if your design handoff wrote itself? In this end‑to‑end demo, I use an AI Agent (inside Cursor) to translate a Figma design into an... The pos...

Naveed Ul-Haq | Feb 5, 2026 |

Graph access with only JS and Fetch

Postman is a popular tool for testing APIs. However, when testing an API like Optimizely Graph that I will be consuming in the front-end I prefer t...

Daniel Halse | Feb 4, 2026

Best Practices for Implementing Optimizely SaaS CMS: A Collective Wisdom Guide

This guide compiles collective insights and recommendations from Optimizely experts for implementing Optimizely SaaS CMS, focusing on achieving...

David Knipe | Feb 4, 2026 |

A day in the life of an Optimizely OMVP: Learning Optimizely Just Got Easier: Introducing the Optimizely Learning Centre

On the back of my last post about the Opti Graph Learning Centre, I am now happy to announce a revamped interactive learning platform that makes...

Graham Carr | Jan 31, 2026