Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Tony Groome 261 posts 804 karma points
    May 13, 2015 @ 12:59
    Tony Groome
    0

    Add a Search on frontend

    Hi All

    I am looking to add a search bar on my front end to search for members. Any ideas how to go about this? I have a list of all members in alphabetical order on my frontend so far.

    I found this http://umbraco.com/help-and-support/video-tutorials/developing-with-umbraco/examine/adding-a-search-to-your-website/TVPlayer# but can only see 2 minutes. I can't find a way to log in with my umbraco.tv subscription.

    Thanks.

    Tony

  • Dennis Aaen 4500 posts 18255 karma points admin hq c-trib
    May 13, 2015 @ 13:03
    Dennis Aaen
    1

    Hi Tony,

    Perhaps you can use the ezSearch package https://our.umbraco.org/projects/website-utilities/ezsearch, it´s pretty nice to use when you need search functionality on your website. It think you could use it because it´s page content

    Hope this could be a solution

    /Dennis

  • Tony Groome 261 posts 804 karma points
    May 13, 2015 @ 14:04
    Tony Groome
    0

    Hi Dennis

    Thanks for that. I got it on the homepage, just have to figure out how to search for members now!It only seems to want to search for content or media. Needs further investigating....

    Tony

  • Tony Groome 261 posts 804 karma points
    May 13, 2015 @ 16:27
    Tony Groome
    0

    Hi Dennis

    Forget the last comment - I misread yours!

    I have the ez-search up and running. It only seems to search through Media and on Content it only finds page titles like Data Comms, Dual Development, .Net, Java... from the image

    Under Homepage

    It doesn't seem to dig deep enough to pick words off the Content pages. So my Members are all displayed on a Content page and it can't see them!

    Any ideas?

    Thanks.

    Tony

  • Jan Skovgaard 11280 posts 23678 karma points MVP 11x admin c-trib
    May 13, 2015 @ 18:12
    Jan Skovgaard
    1

    Hi Tony

    What does your EZsearch configuration look like? You need to specify, which fields it should look at when you're doing your search and, which it should use to display the search results.

    Hope this makes sense and that I have understood your issue.

    /Jan

  • Dennis Aaen 4500 posts 18255 karma points admin hq c-trib
    May 13, 2015 @ 20:01
    Dennis Aaen
    1

    Hi Tony,

    Okay now I see the issue that you have. The way I think that you can solve this case is by adding the macro with the member data into the rich text editor, and then make the rich text editor searchable with the ezSearch package.

    For the documentation on how to add a macro into the rich text editor see here: http://umbraco.tv/videos/implementor/working-with-umbraco-data/macros/using-macros-in-the-rte/

    As Jan says you need to specify, which fields it should look at when you're doing your search and, which it should use to display the search results. Try to see this documentation https://our.umbraco.org/FileDownload?id=7816

    Hope this helps,

    /Dennis

  • Tony Groome 261 posts 804 karma points
    May 14, 2015 @ 09:51
    Tony Groome
    0

    Hi Guys

    Thanks for the pointers. I have the ezsearch macro in the Content editor and it still doesn't find data from the rte. I don't have a macro for the member data, I got this by using a foreach through all the members and displaying them on their own page (alphabetically too - top of the range!!). I am wondering if the macro for the ezsearch needs to be altered to make it search either on the rte where the members are displayed or else through members. My members have custom fields, so it might be easier just to search through the rte. This is the macroPartials.cshtml (sorry it's huge!).

    Thanks a lot.

    Tony

    @using System.Globalization @using System.Text @using System.Text.RegularExpressions @using Examine @using Umbraco.Core.Logging @using Umbraco.Web.Models @inherits Umbraco.Web.Macros.PartialViewMacroPage @{ int parsedInt;

    // Parse querystring / macro parameter
    var model = new SearchViewModel
    {
        SearchTerm = CleanseSearchTerm(("" + Request["q"]).ToLower(CultureInfo.InvariantCulture)),
        CurrentPage = int.TryParse(Request["p"], out parsedInt) ? parsedInt : 1,
    
        PageSize = GetMacroParam(Model, "pageSize", s => int.Parse(s), 10),
        RootContentNodeId = GetMacroParam(Model, "rootContentNodeId", s => int.Parse(s), -1),
        RootMediaNodeId = GetMacroParam(Model, "rootMediaNodeId", s => int.Parse(s), -1),
        IndexType = GetMacroParam(Model, "indexType", s => s.ToLower(CultureInfo.InvariantCulture), ""),
        SearchFields = GetMacroParam(Model, "searchFields", s => SplitToList(s), new List<string> { "nodeName", "metaTitle", "metaDescription", "metaKeywords", "bodyText" }),
        PreviewFields = GetMacroParam(Model, "previewFields", s => SplitToList(s), new List<string> { "bodyText" }),
        PreviewLength = GetMacroParam(Model, "previewLength", s => int.Parse(s), 250),
        HideFromSearchField = GetMacroParam(Model, "hideFromSearchField", "umbracoNaviHide"),
        SearchFormLocation = GetMacroParam(Model, "searchFormLocation", s => s.ToLower(), "bottom")
    };
    
    // Validate values
    if (model.IndexType != UmbracoExamine.IndexTypes.Content &&
        model.IndexType != UmbracoExamine.IndexTypes.Media)
    {
        model.IndexType = "";
    }
    
    if (model.SearchFormLocation != "top"
        && model.SearchFormLocation != "bottom"
        && model.SearchFormLocation != "both"
        && model.SearchFormLocation != "none")
    {
        model.SearchFormLocation = "bottom";
    }
    
    // ====================================================
    // Comment the next if statement out if you want a root
    // node id of -1 to search content across all sites
    // and not just the current site.
    // ====================================================
    if (model.RootContentNodeId <= 0)
    {
        model.RootContentNodeId = Model.Content.AncestorOrSelf(1).Id;
    }
    
    // If searching on umbracoFile, also search on umbracoFileName
    if (model.SearchFields.Contains("umbracoFile") && !model.SearchFields.Contains("umbracoFileName"))
    {
        model.SearchFields.Add("umbracoFileName");
    }
    
    // Check the search term isn't empty
    if(!string.IsNullOrWhiteSpace(model.SearchTerm))
    {
        // Tokenize the search term
        model.SearchTerms = Tokenize(model.SearchTerm);
    
        // Perform the search
        var searcher = ExamineManager.Instance.SearchProviderCollection["ExternalSearcher"];
        var criteria = searcher.CreateSearchCriteria();
        var query = new StringBuilder();
        query.AppendFormat("-{0}:1 ", model.HideFromSearchField);
    
        // Set search path
        var contentPathFilter = model.RootContentNodeId > 0
            ? string.Format("__IndexType:{0} +searchPath:{1} -template:0", UmbracoExamine.IndexTypes.Content, model.RootContentNodeId)
            : string.Format("__IndexType:{0} -template:0", UmbracoExamine.IndexTypes.Content);
    
        var mediaPathFilter = model.RootMediaNodeId > 0
            ? string.Format("__IndexType:{0} +searchPath:{1}", UmbracoExamine.IndexTypes.Media, model.RootMediaNodeId)
            : string.Format("__IndexType:{0}", UmbracoExamine.IndexTypes.Media);
    
        switch (model.IndexType)
        {
            case UmbracoExamine.IndexTypes.Content:
                query.AppendFormat("+({0}) ", contentPathFilter);
                break;
            case UmbracoExamine.IndexTypes.Media:
                query.AppendFormat("+({0}) ", mediaPathFilter);
                break;
            default:
                query.AppendFormat("+(({0}) ({1})) ", contentPathFilter, mediaPathFilter);
                break;
        }
    
        // Ensure page contains all search terms in some way
        foreach (var term in model.SearchTerms)
        {
            var groupedOr = new StringBuilder();
            foreach (var searchField in model.SearchFields)
            {
                groupedOr.AppendFormat("{0}:{1}* ", searchField, term);
            }
            query.Append("+(" + groupedOr.ToString() + ") ");
        }
    
        // Rank content based on positon of search terms in fields
        for (var i = 0; i < model.SearchFields.Count; i++)
        {
            foreach (var term in model.SearchTerms)
            {
                query.AppendFormat("{0}:{1}*^{2} ", model.SearchFields[i], term, model.SearchFields.Count - i);
            }
        }
    
        var criteria2 = criteria.RawQuery(query.ToString());
    
        var results = searcher.Search(criteria2)
           .Where(x => (
                !Umbraco.IsProtected(int.Parse(x.Fields["id"]), x.Fields["path"]) ||
                (
                    Umbraco.IsProtected(int.Parse(x.Fields["id"]), x.Fields["path"]) &&
                    Umbraco.MemberHasAccess(int.Parse(x.Fields["id"]), x.Fields["path"])
                )) && (
                    (x.Fields["__IndexType"] == UmbracoExamine.IndexTypes.Content && Umbraco.TypedContent(int.Parse(x.Fields["id"])) != null) ||
                    (x.Fields["__IndexType"] == UmbracoExamine.IndexTypes.Media && Umbraco.TypedMedia(int.Parse(x.Fields["id"])) != null)
                ))
            .ToList();
    
        model.AllResults = results;
    
        model.TotalResults = results.Count;
        model.TotalPages = (int)Math.Ceiling((decimal)model.TotalResults / model.PageSize);
        model.CurrentPage = Math.Max(1, Math.Min(model.TotalPages, model.CurrentPage));
    
        // Page the results
        model.PagedResults = model.AllResults.Skip(model.PageSize * (model.CurrentPage - 1)).Take(model.PageSize);
    
        LogHelper.Debug<string>("[ezSearch] Searching Lucene with the following query: " + query.ToString());
    
        if (!model.PagedResults.Any())
        {
            // No results found, so render no results view
            if(model.SearchFormLocation != "none")
            {
                @RenderForm(model)
            }
            @RenderNoResults(model)
        }
        else
        {
            // Render out the results
            if (model.SearchFormLocation == "top" || model.SearchFormLocation == "both")
            {
                @RenderForm(model)
            }
            @RenderSummary(model)
            @RenderResultsRange(model)
            @RenderResults(model)
            if(model.TotalPages > 1)
            {
                @RenderPager(model)  
            }
            if (model.SearchFormLocation == "bottom" || model.SearchFormLocation == "both")
            {
                @RenderForm(model)
            }
        }   
    }
    else
    {
        // Empty search term so just render the form
        if(model.SearchFormLocation != "none")
        {
            @RenderForm(model)
        }
    }
    

    }

    @*

    Render Functions

    *@

    @helper RenderForm(SearchViewModel model) {

    }

    @helper RenderSummary(SearchViewModel model) {

    @FormatHtml(GetDictionaryValue("[ezSearch] Summary", "Your search for \"{0}\" matched {1} page(s)."), model.SearchTerm, model.TotalResults)

    }

    @helper RenderResultsRange(SearchViewModel model) { var startRecord = ((model.CurrentPage - 1)*model.PageSize) + 1; var endRecord = Math.Min(model.TotalResults, (startRecord - 1) + model.PageSize);

    <div class="ezsearch-result-count">
        <p>@FormatHtml(GetDictionaryValue("[ezSearch] Results Range", "Showing results <strong>{0}</strong> to <strong>{1}</strong>."), startRecord, endRecord)</p>
    </div>
    

    }

    @helper RenderResults(SearchViewModel model) {

    @foreach (var result in model.PagedResults) { switch (result.Fields["__IndexType"]) { case UmbracoExamine.IndexTypes.Content: var contentItem = Umbraco.TypedContent(result.Fields["id"]); @RenderContentResult(model, contentItem) break; case UmbracoExamine.IndexTypes.Media: var mediaItem = Umbraco.TypedMedia(result.Fields["id"]); @RenderMediaResult(model, mediaItem) break; } }
    }

    @helper RenderContentResult(SearchViewModel model, IPublishedContent result) {

    @result.Name

    @foreach (var field in model.PreviewFields.Where(field => result.HasValue(field))) {

    @Highlight(Truncate(Umbraco.StripHtml(result.GetPropertyValue(field).ToString()), model.PreviewLength), model.SearchTerms)

    break; }
    }

    @helper RenderMediaResult(SearchViewModel model, IPublishedContent result) {

    @result.Name

    @foreach (var field in model.PreviewFields.Where(field => result.HasValue(field))) {

    @Highlight(Truncate(Umbraco.StripHtml(result.GetPropertyValue(field).ToString()), model.PreviewLength), model.SearchTerms)

    break; }
    }

    @helper RenderPager(SearchViewModel model) {

    @if (model.CurrentPage > 1) { @(GetDictionaryValue("[ezSearch] Previous", "Previous")) } else { @(GetDictionaryValue("[ezSearch] Previous", "Previous")) }

            @for (var i = 1; i <= model.TotalPages; i++)
            {
                if(i == model.CurrentPage) {
                    <span class="page">@i</span>
                } else {
                    <a class="page" href="?q=@(model.SearchTerm)&p=@(i)">@i</a>
                }
            }
    
            @if (model.CurrentPage < model.TotalPages) {
                <a class="next" href="?q=@(model.SearchTerm)&p=@(model.CurrentPage + 1)">@(GetDictionaryValue("[ezSearch] Next", "Next"))</a>
            } else {
                <span class="next">@(GetDictionaryValue("[ezSearch] Next", "Next"))</span>
            }
        </p>
    </div>
    

    }

    @helper RenderNoResults(SearchViewModel model) {

    @FormatHtml(GetDictionaryValue("[ezSearch] No Results", "No results found for search term {0}."), model.SearchTerm)

    }

    @functions { // ================================================== // Helper Functions //==================================================

    // Cleanse the search term
    public string CleanseSearchTerm(string input)
    {
        return Umbraco.StripHtml(input).ToString();
    }
    
    // Splits a string on space, except where enclosed in quotes
    public IEnumerable<string> Tokenize(string input)
    {
        return Regex.Matches(input, @"[\""].+?[\""]|[^ ]+")
            .Cast<Match>()
            .Select(m => m.Value.Trim('\"'))
            .ToList();
    }
    
    // Highlights all occurances of the search terms in a body of text
    public IHtmlString Highlight(IHtmlString input, IEnumerable<string> searchTerms)
    {
        return Highlight(input.ToString(), searchTerms);
    }
    
    // Highlights all occurances of the search terms in a body of text
    public IHtmlString Highlight(string input, IEnumerable<string> searchTerms)
    {
        input = HttpUtility.HtmlDecode(input);
    
        foreach (var searchTerm in searchTerms)
        {
            input = Regex.Replace(input, Regex.Escape(searchTerm), @"<strong>$0</strong>", RegexOptions.IgnoreCase);
        }
    
        return new HtmlString(input);
    }
    
    // Formats a string and returns as HTML
    public IHtmlString FormatHtml(string input, params object[] args)
    {
        return Html.Raw(string.Format(input, args));
    }
    
    // Gets a dictionary value with a fallback
    public string GetDictionaryValue(string key, string fallback)
    {
        var value = Umbraco.GetDictionaryValue(key);
    
        return !string.IsNullOrEmpty(value)
            ? value
            : fallback;
    }
    
    // Truncates a string on word breaks
    public string Truncate(IHtmlString input, int maxLength)
    {
        return Truncate(input.ToString(), maxLength);
    }
    
    // Truncates a string on word breaks
    public string Truncate(string input, int maxLength)
    {
        var truncated = Umbraco.Truncate(input, maxLength, true).ToString();
        if (truncated.EndsWith("&hellip;"))
        {
            var lastSpaceIndex = truncated.LastIndexOf(' ');
            if(lastSpaceIndex > 0)
            {
                truncated = truncated.Substring(0, lastSpaceIndex) + "&hellip;";
            }
        }
    
        return truncated;
    }
    
    // Gets a macro parameter in a safe manner with fallback
    public string GetMacroParam(PartialViewMacroModel model, string key, string fallback)
    {
        return GetMacroParam(model, key, s => s, fallback);
    }
    
    // Gets a macro parameter in a safe manner with fallback
    public TType GetMacroParam<TType>(PartialViewMacroModel model, string key, Func<string, TType> convert, TType fallback)
    {
        if(!model.MacroParameters.ContainsKey(key))
        {
            return fallback;
        }
    
        var value = model.MacroParameters[key];
        if(value == null || value.ToString().Trim() == "")
        {
            return fallback;
        }
    
        try
        {
            return convert(value.ToString());
        }
        catch (Exception)
        {
            return fallback;
        }
    }
    
    // Splits a coma seperated string into a list
    public IList<string> SplitToList(string input)
    {
        return input.Split(',')
            .Select(f => f.Trim())
            .Where(f => !string.IsNullOrEmpty(f))
            .ToList();
    } 
    
    // ==================================================
    //  Helper Classes
    //==================================================
    
    public class SearchViewModel
    {
        // Query Parameters
        public string SearchTerm { get; set; }
        public IEnumerable<string> SearchTerms { get; set; }
        public int CurrentPage { get; set; }
    
        // Options
        public int RootContentNodeId { get; set; }
        public int RootMediaNodeId { get; set; }
        public string IndexType { get; set; }
        public IList<string> SearchFields { get; set; }
        public IList<string> PreviewFields { get; set; }
        public int PreviewLength { get; set; }
        public int PageSize { get; set; }
        public string HideFromSearchField { get; set; }
        public string SearchFormLocation { get; set; }
    
        // Results
        public int TotalResults { get; set; }
        public int TotalPages { get; set; }
    
        public IEnumerable<SearchResult> AllResults { get; set; }
        public IEnumerable<SearchResult> PagedResults { get; set; }
    }
    

    }

  • Tony Groome 261 posts 804 karma points
    May 14, 2015 @ 10:08
    Tony Groome
    0

    Hi Guys

    I've just noticed something interesting. I have two search bars working, one on my homepage and the other on my Staff Listing page (where all the staff are listed). The search on the homepage seems to only search for my links, any text on the homepage which is displayed from the Content Editor is ignored.

    So over on the Staff Listing page nothing is found in the search as there are no links from it, no text is displayed (which is the staff names and their contact details) in a search either.

    Hopefully this makes sense. Thanks.

    Tony

  • Dennis Aaen 4500 posts 18255 karma points admin hq c-trib
    May 14, 2015 @ 11:18
    Dennis Aaen
    1

    Hi Tony,

    Perhaps it can help you if you see this post https://our.umbraco.org/projects/website-utilities/ezsearch/bugs-feedback-suggestions/50405-open-search-results-in-a-new-page, try to see my comment, I think it can help you to get it work.

    I should be necessary to change anything in the files to get the ezSeach search in content or media, you just need to configure which fields it should look into.

    Hope this helps,

    /Dennis

  • Tony Groome 261 posts 804 karma points
    May 14, 2015 @ 12:40
    Tony Groome
    0

    Hi Dennis

    Thanks for your links. I don't understand what you did there. In theory it makes sense, like Jan said you need to specify, which fields it should look at when you're doing your search and, which it should use to display the search result. I have no idea how to do this in Umbraco....

    It's like digging a bigger hole! Thanks.

    Tony

  • Tony Groome 261 posts 804 karma points
    May 15, 2015 @ 10:24
    Tony Groome
    0

    Hi Guys

    Glad to see the forum is back up and running - hope the nuke went down well!

    During the quiet time (or very noisy depending on where you are!) I went through ezSearch and discovered that it is finding my Media names, the names of the jpg images I have uploaded and in Content the page names. So would it be very unorthodox to have a page for every member and let the search find them that way, there could be 120 pages, though I would save them in folders according to their branches, for neatness. 99.5% of them won't need to access the site, they will be just viewing.

    Thanks.

    Tony

  • Tony Groome 261 posts 804 karma points
    May 15, 2015 @ 13:56
    Tony Groome
    100

    Hi Guys

    Just to finish this out and mark as solved. What I did was scrap the Members section and just set up a page for each member of staff here. We have 8 branches so I made a branch page and under each branch page there are staff pages. So, in effect each member of staff gets their own page. The page name is the member of staff's name and this shows up in the search. Even just the first letter like T, brings up all the T's - it's very powerful and fast. Later on we will give each branch manager a login to the back office to add staff members as they hire, so spreading the load!

    Thanks for all the help Dennis and Jan. :)

    Tony

Please Sign in or register to post replies

Write your reply to:

Draft