Copied to clipboard

Flag this post as spam?

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


  • marie 22 posts 132 karma points
    Oct 09, 2017 @ 20:55
    marie
    0

    Filtering Examine Search results by field values

    I have a doctype that goes in three directions: an article page, an external link, or an internal link. Since the doctype has a template regardless of where it goes, Examine Search treats it the same and directs the linked search result to what would be the Article page.

    For items that are either supposed to go to an external URL or link to an internal PDF, this results in a "Page Not Found" error.

    Is there any way to either filter any results with values in the "Internal Link" or "External link" fields out of Search entirely, or adjust the way Examine links these items in the search result? The latter would be preferred, but I'm not going to dismiss anything that actually works, regardless.

    Thanks.

    EDITED TO ADD

    I've noticed that the SiteSearch.cshtml page has this code, and I'm thinking it's where I'd go for any results manipulation. Does anyone think anything in here might lend itself to an alteration in which an if statement detects whether or not a result has value in property field "externalLink" or "internalLink" (which is a media picker, but we'll deal with that later):

        @inherits Umbraco.Web.Macros.PartialViewMacroPage
    @using Examine.LuceneEngine.SearchCriteria
    
    @{
        try
        {
            string query = Request.Form["SearchQuery"];
    
            <div>
                @if (!string.IsNullOrEmpty(query))
                {
                    var searchProvider = Examine.ExamineManager.Instance.SearchProviderCollection["WebsiteSearcher"];
                    var content = searchProvider.Search(query, false);
    
                    var results = content.Select(x => new SiteSearchResult()
                        {
                            Id = Convert.ToInt32(x.Fields["id"]),
                            Title = x.Fields["nodeName"],
                            Summary = GetPreviewText(x.Fields),
                            Score = x.Score,
                            Url = Umbraco.NiceUrl(Convert.ToInt32(x.Fields["id"])),
                            ParentUrl = Umbraco.NiceUrl(Convert.ToInt32(x.Fields["parentID"])),
                            IsPage = x.Fields["template"] != "0"
    
                        }).OrderByDescending(y => y.Score).ToList();
    
                    results.RemoveAll(x => x.Url == "#");
    
                    <p>for <i>@query</i> returned @results.Count() result@(results.Count() == 1 ? "" : "s")</p>
    
                    if (results != null && results.Count() > 0)
                    {
                        <ul>
                            @foreach (var item in results)
                            {
                                <li>
                                    @if (!item.IsPage && !string.IsNullOrEmpty(item.ParentUrl))
                                    {
                                        <a href="@item.ParentUrl">@item.Title</a>
                                        <p class="preview-text">
                                            @item.Summary
                                        </p>
                                    }
    
                                    else
                                    {
                                        <a href="@item.Url">@item.Title</a>
                                        <p class="preview-text">
                                            @item.Summary
                                        </p>
                                    }
                                </li>
                            }
                        </ul>
                    }
                    else
                    {
                        <span>No results found.</span>
                    }
                }
            </div>
        }
        catch (Exception ex)
        {
            <span>@ex.Message<br />@ex.StackTrace</span>
        }
    
    @functions{
    
        public class SiteSearchResult
        {
            public int Id { get; set; }
            public string Title { get; set; }
            public string Summary { get; set; }
            public float Score { get; set; }
            public string Url { get; set; }
            public string ParentUrl { get; set; }
            public bool IsPage { get; set; }
        }
    
        public string GetPreviewText(IDictionary<string, string> fields)
        {
            var previewText = "";
    
            if (fields.ContainsKey("previewText"))
            {
                previewText = fields["previewText"];
            }
            else if (fields.ContainsKey("jobTitle"))
            {
                previewText = fields["jobTitle"];
            }
            else if (fields.ContainsKey("bodyText"))
            {
                previewText = fields["bodyText"];
                previewText = previewText.Substring(0, Math.Min(previewText.Length, 500)) + " ...";
            }
            else if (fields.ContainsKey("leftContent"))
            {
                previewText = fields["leftContent"];
                previewText = previewText.Substring(0, Math.Min(previewText.Length, 500)) + " ...";
            }
    
            return Umbraco.StripHtml(previewText).ToString();
        }
    
  • Nigel Wilson 944 posts 2076 karma points
    Oct 16, 2017 @ 18:28
    Nigel Wilson
    0

    Hi Marie

    I am about to attack a similar issue with a site I have whereby I will need to "massage" the search results as desired.

    So the approach I have been thinking about is a custom model, using a controller action to retrieve the examine search result collection, loop through the results and build a list of items to then render on the page.

    Whilst looping through the results, you can exclude them if needed, or build the desired URL for the result based on your document type properties.

    I ahve built something similar in a previous job but don't have access to that code anymore, so my starting point will be the following : https://our.umbraco.org/documentation/reference/searching/examine/examine-manager

    Hope this helps.

    Cheers, Nigel

  • marie 22 posts 132 karma points
    Oct 18, 2017 @ 16:23
    marie
    0

    Hello Nigel,

    Unfortunately, I am extremely ignorant of Examine in general and I honestly have no idea how to implement much of anything related to it.

    But if you figure out how to make the adjustments and are willing to come back give a step-by-step instruction, that would be incredibly helpful!

  • marie 22 posts 132 karma points
    Nov 01, 2017 @ 16:45
    marie
    0

    So is there just no solution for this sort of thing, then?

  • Brad McDavid 11 posts 123 karma points
    Nov 01, 2017 @ 18:59
    Brad McDavid
    0

    Hi Marie,

    How about creating a custom MVC controller for that doctype to perform the link checks and redirect accordingly if its internal/external or CMS content?

    Here is a link to documentation for creating a custom controller:

    https://our.umbraco.org/documentation/reference/routing/custom-controllers

    Hope this helps,

    Brad

  • marie 22 posts 132 karma points
    Nov 02, 2017 @ 15:40
    marie
    0

    This sounds like it might be a good solution, but the provided documentation doesn't really walk me through what I'd need to do very well. I'm not familiar enough with custom controllers to know how to take the documentation and make it do what I need it to do for my particular case.

    Attempts to make this work leads to errors thrown, probably where I failed to apply my information to the example information correctly.

  • Brad McDavid 11 posts 123 karma points
    Nov 02, 2017 @ 16:26
    Brad McDavid
    100

    I did a quick test against a new solution using the starter kit blog post. Here is the controller I made:

    using System.Web.Mvc;
    using Umbraco.Web.Models;
    using Umbraco.Web.Mvc;
    using Umbraco.Web;
    using Umbraco.Core.Models;
    
    namespace _UmbracoTest.Controllers
    {
        /// <summary>
        /// Example Controller for docType alias 'blogPost'
        /// </summary>
        public class BlogPostController : RenderMvcController
        {
            public override ActionResult Index(RenderModel renderModel)
            {
                var externalLink = renderModel.Content.GetPropertyValue<string>("externalLink"); // example as simple text string
    
                if (!string.IsNullOrWhiteSpace(externalLink))
                {
                    return Redirect(externalLink);
                }
    
                var internalLink = renderModel.Content.GetPropertyValue<IPublishedContent>("internalLink"); // example property type is media picker
    
                if (internalLink != null)
                {
                    return Redirect(internalLink.Url);
                }
    
                // fallback to default behaviour
                return base.Index(renderModel);
            }
        }
    }
    

    What was the error message you got when using a custom controller?

    -Brad

  • marie 22 posts 132 karma points
    Nov 02, 2017 @ 20:04
    marie
    0

    The error was the code not recognizing "RenderModel," but I was probably just missing a Using statement.

    Using your code, there are no errors -- but I still can't make the search page send URLs to external or internal links. I'm using it on docType alias "ArticleItem," which is the doctype that actually has the internal and external link fields. Would the controller not working have to do with the Search Page (which is a Partial View Macro within a template) being what's writing to the page, or should this controller universally recognize and redirect all "ArticleItem" docTypes?

    Thank you for your patience, by the way! I'm still rather new to MVC.

  • Brad McDavid 11 posts 123 karma points
    Nov 02, 2017 @ 20:22
    Brad McDavid
    0

    Hi Marie,

    So your controller should have the name 'ArticleItemController' to follow the MVC convention.

    Your search results macro should be using the content's URL property. Don't worry that it doesn't match the external/internal link. Whenever that link is clicked, your custom ArticleItemController will then decide how to proceed based in the properties for the given RenderModel.Content in the Index function.

    The nice part is handling the redirect logic in the controller is it works in many different areas, for example if an article item were selected by a related links property for another document type.

    Hope this helps,

    Brad

  • marie 22 posts 132 karma points
    Nov 03, 2017 @ 14:38
    marie
    0

    Hi Brad,

    It looks like the code works successfully for external links, so thank you! The reason why it wasn't working before was because of some pre-existing redirects I didn't know were on the site, which overrode the code on my local copy. When the code was applied to the live site, the external links redirected as intended.

    It doesn't seem like it's applying correctly to internal links, though.

  • Brad McDavid 11 posts 123 karma points
    Nov 03, 2017 @ 15:07
    Brad McDavid
    0

    Glad to hear its mostly working!

    In my controller example, I made the assumption the internal link property was using a media picker data type. You may just need to change IPublishedContent to string, similar to the External Url, and see if that works.

    -Brad

  • marie 22 posts 132 karma points
    Nov 06, 2017 @ 13:59
    marie
    0

    No, the internal link property is a media picker datatype, which is why I don't get how it's not working.

  • Brad McDavid 11 posts 123 karma points
    Nov 06, 2017 @ 14:46
    Brad McDavid
    0

    Hi Marie,

    Are you able to provide an example of how you are getting the internal link property in other areas of your site?

    Thanks,

    Brad

  • marie 22 posts 132 karma points
    Nov 06, 2017 @ 16:53
    marie
    0

    The code for that particular section is:

    if (article.HasValue("internalLink"))
                                {
                                    var mediaItem = Umbraco.Media(article.internalLink);
    
                                    <a href="@mediaItem.umbracoFile" target="">@article.title</a>  
                                }
    
  • Brad McDavid 11 posts 123 karma points
    Nov 06, 2017 @ 18:27
    Brad McDavid
    0

    That looks to be using the older dynamic way. I tried the below on a test site for using Umbraco 7.7.4 and it worked in the MVC controller:

        var internalLink = renderModel.Content.GetProperty("internalLink");
    
        if (internalLink.HasValue)
        {
            var publishedMedia = internalLink.Value as IPublishedContent;
    
            if (publishedMedia != null)
            {
                return Redirect(publishedMedia.Url);
            }
        }
    

    If that code doesn't work, then most likely internalLink.Value isn't IPublishedContent, but not sure what it would be otherwise. In that case, if you can run the site locally, you can run in debug mode to attach to the controller and inspect further.

    Hope this helps,

    -Brad

  • marie 22 posts 132 karma points
    Nov 08, 2017 @ 15:17
    marie
    0

    You've been a lot of help, Brad, but this sadly still doesn't work for my media picker internal links. And I can't get things working locally because of all the implanted redirects or hard-coded addresses that just send me to the live site whenever I click a link. Not really sure why the original developers of the site put those in there, but they're causing a few testing problems.

    I think I might be able to stop the internal link from returning a Page Not Found error, which means my last-ditch solution might have to be just linking to the intended PDF on the page. It adds extra clicks and it's really not what I want to do, but if it's the only way to get the internal link where it needs to go, I guess that's what has to be done.

Please Sign in or register to post replies

Write your reply to:

Draft