Copied to clipboard

Flag this post as spam?

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


  • Kris Janssen 210 posts 569 karma points c-trib
    Jul 21, 2014 @ 11:41
    Kris Janssen
    1

    Articulate integration in existing site

    Hi,

    First of all, very nice work on this package. It' s really nice to see people create these kinds of rich functionality as open source.

    I am currently trying to integrate the blog functionality in my own site.

    Because I understand that the blog is more standard MVC there are some limitations in this respect:

    1. To make the blog fit in my existing structure, I placed the root blog node under my Home page (so not the true content root). This is causing issues if you have Hostnames defined. I think because ArticulateRoutes.cs uses (node.Url.EnsureEndsWith('/') + "a-new/{id}").TrimStart('/'), and .Url will include the defined hostname. Using Node.UrlName could fix this but I am not experienced enough to judge if this could have other side effects.
    2. After moving the blog root I started creating a Theme using the contents of my normal master pages. This works nicely mostly, except that there is some obvious duplication of layout. But not really an issue.
    3. I then copied over the contents of the Razor macros I use for e.g. navigation rendering and here the real purpose of my post comes along:

    My site relies on restricted pages. In my Nav Macro I use @Umbraco.MemberHasAccess(). This helper is of course not directly available in IMasterModel.

    I solved this in a hacky way by adding a private field to MasterModel.cs and passing this a new UmbracoHelper upon construction.

    The UmbracoHelper is then exposed with an added public property Umbraco after which I can call @Model.Umbraco.MemberHasAccess() from my blog them.

    Also, all references to CurrentPage can easily be replaced by (IPublishedContent)Model.

    This all seems to work but I am not quite sure this is the best way to do it. I also had to make my model reference MasterModel instead of IMasterModel because I didn't want to put my addition in the interface.

    However, if it were, would you consider adding this to the Articulate source to make the options for integration in existing projects/site somewhat more flexible or are there fundamental objections to doing such a thing?

    Your expert thoughts on this would be greatly appreciated :)

    Kris

  • Shannon Deminick 1524 posts 5269 karma points MVP 2x
    Jul 22, 2014 @ 18:52
    Shannon Deminick
    100

    In your views you'll see something like this (i.e. this is for the Posts view):

    @model Articulate.Models.PostModel

    This means that your view is a standard MVC view with nothing really that cool going on. However, if you make your view inherit from the Umbraco base view with this model, you should then have instant access to all the normal Umbraco things that you use (apart from dynamics like 'currentpage'):

    So change: @model Articulate.Models.PostModel

    to:

    @inherits Umbraco.Web.Mvc.UmbracoViewPage

    And just an FYI, this syntax:

    @model Articulate.Models.PostModel

    is actually just syntactical sugar and gets compiled to this:

    @inherits System.Web.Mvc.WebViewPage

    Regarding your hostname issue, can you please create an issue on GitHub for this?

  • Kris Janssen 210 posts 569 karma points c-trib
    Jul 22, 2014 @ 20:12
    Kris Janssen
    0

    Thanks for the update,

    It was only after this post that I actually noticed that the categories view @inherits UmbracoViewPage<Articulate.Models.IMasterModel>. Whereas most others seem to just inherit their respective models...

    So likely if UmbracoViewPage is used, I will get the flexibility I want for plugging it into my site, right? Should have actually thought of that before, I did the same when plugging Warrens Standard Membership project into my site.

    I have put an issue on GH for the hostnames stuff.

    Cheers,

    Kris

  • Shannon Deminick 1524 posts 5269 karma points MVP 2x
    Jul 22, 2014 @ 20:17
    Shannon Deminick
    1

    just noticed that my syntax didn't come through properly in my last post, here's what it was meant to look like:

    So change: @model Articulate.Models.PostModel
    

    to:

    @inherits Umbraco.Web.Mvc.UmbracoViewPage<Articulate.Models.PostModel>
    

    And just an FYI, this syntax:

    @model Articulate.Models.PostModel
    

    is actually just syntactical sugar and gets compiled to this:

    @inherits System.Web.Mvc.WebViewPage<Articulate.Models.PostModel>
    

    I think when creating those views I was just making them based on what I required and for what I needed I didn't need the umbraco helpers, etc...

    So yes, if you change the @model syntax to the @inherits syntax with

     UmbracoViewPage<T>
    

    Where T is the correct model for that page, then you'll get all of the Umbraco bits.

  • Patrick Scott 70 posts 110 karma points c-trib
    Aug 07, 2014 @ 10:37
    Patrick Scott
    0

    I've got a similar issue to this, I am trying to get the master.cshtml page to link to my sites master page (Layout = "~/views/Main.cshtml") so I don't need to duplicate the sites structure.

    I have tried 

    @inherits Umbraco.Web.Mvc.UmbracoViewPage<Articulate.Models.IMasterModel>
    

    and I get the error 

    The model item passed into the dictionary is of type 'Umbraco.Web.Models.RenderModel', but this dictionary requires a model item of type 'Articulate.Models.IMasterModel'.

    If I try

    @inherits Umbraco.Web.Mvc.UmbracoTemplatePage<Articulate.Models.IMasterModel>
    

    I get a compile error 

     

    Is thee a way to do this without duplicating my sites layout into master.cshtml ?

     

  • Shannon Deminick 1524 posts 5269 karma points MVP 2x
    Aug 07, 2014 @ 18:58
    Shannon Deminick
    0

    This all depends on if you need a strongly typed master page.

    First, the generic version of UmbracoTemplatePage only accepts a type of IPublishedContent and class reference, IMasterModel is neither of these so you will definitely get errors trying that. Since all of the models that Articulate uses are instances of IPublishedContent, you can just try:

    @inherits Umbraco.Web.Mvc.UmbracoViewPage<IPublishedContent>
    

    Of course if you are using the articulate helper methods in your master page you'd still need a reference to IMasterModel, since you know that all Articulate models are this type, you'd have to cast

    @{
        var articulateMasterModel = Model as IMasterModel;
        if (articulateMasterModel == null)
        {
            //couldn't convert, throw exception?
        }
    }
    

    You can always use dynamic too which will work in all cases:

    @model dynamic
    

    But then you'll probably have to cast this internally in your view too - depending on the child view you are rendering.

    All of this is really up to how you are structuring your views and what your master view is doing, there's no single correct answer and various ways to structure your view hierarchies.

    @inherits Umbraco.Web.Mvc.UmbracoViewPage<dynamic>
    
  • Patrick Scott 70 posts 110 karma points c-trib
    Aug 10, 2014 @ 11:31
    Patrick Scott
    0

    Thanks, the only way I could get it working is with 

    @model dynamic
    

    in master.cshtml. List.cshtml and Post.cshtml work with the format:

    @inherits Umbraco.Web.Mvc.UmbracoViewPage<Articulate.Models.ListModel>
    

     

    For tags.cshtml I had to change the source code in TagListModel.cs as the class TagListModel was implementing iMasterModel rather than inheriting MasterModel like the other models. I don't know if this was done this way for a reason, but everything is working fine at the moment. I will add an issue to GitHub with the details in for you.

     

     

  • Jeroen Breuer 4908 posts 12265 karma points MVP 4x admin c-trib
    Aug 10, 2014 @ 20:05
    Jeroen Breuer
    2

    Hello,

    It might be good to know that you can also change the models that Articulate returns to the view. In the Umbraco 7.1.5 nightlies there is an event you can use for this: http://issues.umbraco.org/issue/U4-5065

    An example for the event:

    public class UmbracoEvents : ApplicationEventHandler
    {
        protected override void ApplicationStarting(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
        {
        }
    
        protected override void ApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
        {
            PreRenderViewActionFilterAttribute.ActionExecuted += PreRenderViewActionFilterAttribute_ActionExecuted;
        }
    
        protected void PreRenderViewActionFilterAttribute_ActionExecuted(object sender, ActionExecutedEventArgs e)
        {
            if (e.Controller.GetType().ToString() == "Articulate.Controllers.ArticulateRichTextController")
            {
                var oldModel = (Articulate.Models.PostModel)e.Model;
                var newModel = ModelLogic.GetModel<Umbraco.Extensions.Models.PostModel>();
                newModel.PostModelObject = oldModel;
                e.Model = newModel;
            }
        }
    }

    Jeroen

     

  • Matt Taylor 873 posts 2086 karma points
    Feb 18, 2021 @ 15:07
    Matt Taylor
    0

    Hi Jeroen,

    Interesting that you post this because I'm using your Hybrid Framework for Umbraco v7 architecture for my Umbraco 8 project.

    Do you think this could be an answer to the problem I have posted below?

    Thanks,

    Matt

  • Andy 6 posts 76 karma points
    Jun 04, 2016 @ 21:44
    Andy
    0

    Hello,

    This post seems to reference exactly what I am trying to do. I have researched this a lot and tried a lot of ways without luck.

    I have an Umbraco site with typical templates and doc types.

    /Views/Master.cshtml wraps all templates of my entire site.

    In Articulate theme (/App_Plugins/Articulate/Themes/) I copied an existing theme to my own to use as a base - generically called 'MyTheme'.

    I am trying to wrap /AppPlugins/Articulate/Themes/MyTheme/List.cshtml and /AppPlugins/Articulate/Themes/MyTheme/Post.cshtml with my /Views/Master.cshtml used for the entire site.

    On List.cshtml I have tried a number of things, but based on this post I currently have...

    @using Articulate
    

    @using Articulate.Models

    @using Umbraco.Core

    @inherits Umbraco.Web.Mvc.UmbracoViewPage< IPublishedContent >

    @{ Layout = "/Views/Master.cshtml"; }

    @if (!Model.Children.Any())

    {
        <article>No blog posts found</article>        
    }
    else
    {
        foreach (var post in Model.Children<PostModel>())
        {
            <article class="preview">
                <header>
                    <h1 class="post-title"><a href="@post.Url">@post.Name</a></h1>
                    <div class="post-meta">
                        <time datetime="@post.PublishedDate.ToString("yyyy-MM-dd")">
                            @post.PublishedDate.ToString("dddd, MMMM dd, yyyy")
                        </time>
                    </div>
                </header>
                <section class="post-excerpt">
                    @if (!post.PostImageUrl.IsNullOrWhiteSpace())
                    {
                        var thumbnail = post.GetCropUrl("postImage", "thumbnail");
                        if (!thumbnail.IsNullOrWhiteSpace())
                        {
                            <img class="thumb" src="@thumbnail" alt="@post.Name" />
                        }
                    }
                    <p>
                        @post.Excerpt&hellip;
                    </p>
                    <p class="readmore">
                        <a href="@post.Url">Read this article <i class="fa fa-chevron-circle-right"></i></a>
                    </p>
                </section>
            </article>
        }
    
    }
    

    The error that I get is

    Cannot bind source content type Articulate.Models.ListModel to model content type Umbraco.Web.PublishedContentModels.Master.

    --

    Any help is much appreciated.

  • Shannon Deminick 1524 posts 5269 karma points MVP 2x
    Jun 06, 2016 @ 10:16
    Shannon Deminick
    0

    Hi Andy,

    You are doing the opposite of what is required. In ASP.NET MVC, the model that is rendering the page (regardless of the layout) must match the model that the page (not layout) is using.

    Layouts are special, they will always be given the model of the current page that is rendering. So, if your layout isn't compatible with the model that is rendering then you need to re-think some things.

    The change you made above is incorrect, you cannot change the model of List.cshtml because that page requires a specific model: Articulate.Models.ListModel

    This model Articulate.Models.ListModel implements IPublishedContent, therefore, your layout could have a model like: @inherits Umbraco.Web.Mvc.UmbracoViewPage< IPublishedContent > which would be compatible with Articulate.Models.ListModel

    Making more sense?

  • Barry 7 posts 79 karma points
    Sep 14, 2016 @ 09:40
    Barry
    1

    When I was trying to set this up myself, I found an article that gave a step-by step to do this, it covers most of the above and was pretty easy to follow:

    https://www.marceldigital.com/blog/2015/09/how-to-setup-an-articulate-blog-package-to-an-existing-umbraco-layout

  • Joey Kincer 51 posts 83 karma points
    Dec 12, 2016 @ 08:45
    Joey Kincer
    0

    I've been trying to do the same thing as other posters here. My blog root is a few levels deep with 2 inherited layouts and a lot of Umbraco methods/properties being used in both, which is causing complications when applying the @inherits Umbraco.Web.Mvc.UmbracoViewPage<IPublishedContent> in the ancestor layout templates.

    I reassigned CurrentPage with (IPublishedContent)Model as Kris suggested, but I'm running into several limitations:

    1) queryable list "does not contain a definition for 'Add'"

    2) no access to the properties via Node.Property

    I'm sure there are more errors in the template, but I can't even get past the first few lines, so maybe just fixing these will apply to the rest. Hoping I'm just missing a simple reference call/cast and don't have to reprogram the entire template just to satisfy the needs of the Articulate blog.

    Here's an example where the last two lines give me errors (FYI this all works fine when the normal UmbracoTemplatePage inheritance is called):

     var CurrentPage = (IPublishedContent)Model;
     var homepage = CurrentPage.AncestorOrSelf(2);
     var subpages = homepage.Children().Where("Visible");
     var jhppages = subpages;
     jhppages.Add(homepage); 
        [above line does not contain definition for "Add"]
     var homeclass = homepage.umbracoUrlName; 
        [above line 'Umbraco.Core.Models.IPublishedContent' does not contain a definition for 'umbracoUrlName']
    

    Next-Morning-Thought Edit: I understand I'm losing access to DynamicPublishedContent by having to use the Strongly Typed inheritance, which is probably why the Node.Property syntax isn't working, but there's way too much code to go through and have to convert all that. I can't even find any documentation to convert the .Add() method to Strongly Typed.

    I'm not too versed in the nature between Dynamic and Strongly Typed (always used the former), so it's difficult to know the steps to take. Is there a simple way to revive the dynamic nature of the node objects so I can continue to utilize the DynamicPublishedContent features? That way I could leave most of my code untouched. Or is there simply no way around being forced to use Strongly Typed in order to use the Articulate blog within an existing template?

  • Sebastian 1 post 71 karma points
    Dec 28, 2016 @ 07:43
    Sebastian
    0

    First of all, thanks for the really cool plugin, even though i have some problems with getting everything to work the way i want it seems really well thought out and feature rich :)

    But I too am fighting with integrating Articulate into an existing site with an existing layout.

    After much reading Online what i managed so far is having a List.chstml which display me a list of Blogposts

    @using Articulate
    @using Umbraco.Core.Models
    
    @inherits Umbraco.Web.Mvc.UmbracoViewPage<IPublishedContent>
    @{
        Layout = "~/Views/Shared/_Layout.cshtml";
        var articulateModel = (Articulate.Models.ListModel)Model;
    }
    <div class="container">
        <div class="header-push"></div>
        <div class="breadcrumb-push"></div>
        <h1>Blog</h1>
        @foreach (var post in articulateModel.Children)
        {
            <h1><a class="postheader taggedlink" href="@post.Url">@post.Name</a></h1>
        }
    </div>
    

    And a post.cshtml to display my posts

    @using Articulate
    @using Umbraco.Core.Models
    @inherits Umbraco.Web.Mvc.UmbracoViewPage<Articulate.Models.PostModel>
    @{
        Layout = "~/Views/Shared/_Layout.cshtml";
        var articulateModel = (Articulate.Models.PostModel)Model;
    }
    <div class="container">
        <div class="header-push"></div>
        <div class="breadcrumb-push"></div>
        <article class="post tag-ghost-tag">
    
            <span class="post-meta">
                <time datetime="@articulateModel.PublishedDate.ToString("yyyy-MM-dd")">
                    @articulateModel.PublishedDate.ToString("dddd, MMMM dd, yyyy")
                </time>
                <br /><br /><span>Tags: @Html.ThemedPartial(articulateModel, "PostTags")</span>
            </span>
    
            <h1 class="post-title">@articulateModel.Name</h1>
    
            <section class="post-content">
                @articulateModel.Body
    </section>
    
            <footer class="post-footer">
                @if (articulateModel.EnableComments)
                {
                    @Html.ThemedPartial(articulateModel, "Comments")
                }
            </footer>
    
        </article>
    </div>
    

    But what i am totally unable to do, no matter what i try is to get the image of the current post.

    I had a look at how the other themes do it

    @if (!Model.PostImageUrl.IsNullOrWhiteSpace())
    {
        var cropUrl = Model.GetCropUrl("postImage", "blogPost");
        if (!cropUrl.IsNullOrWhiteSpace())
        {
            <img class="postImage" alt="@Model.Name" src="@cropUrl" />
        }
    }
    

    But i can't get this to work for me at all.

    It always complains that "PostModel does not contain a definition for GetCropUrl" . I assume this should be very simple to solve but since i am very new to Umbraco and ASP.Net in general i am totally at loss here.

    I have tried to read into general documentation to get a better grasp of what exactly i am doing wrong but i would really appreciate a quick pointer.

  • Shannon Deminick 1524 posts 5269 karma points MVP 2x
    Feb 23, 2017 @ 23:21
    Shannon Deminick
    0

    GetCropUrl should not be used this way, the way you are trying to use it is Obsolete. GetCropUrl returns a URL and as such it is a method on the UrlProvider so please use that instead: Url.GetCropUrl(Model, "postImage", "blogPost")

  • Bobi 346 posts 950 karma points
    Feb 23, 2017 @ 16:07
    Bobi
    0

    Has anyone figured this out? I just want to include a list of recent blog posts in my homepage...

    Homepage starts off with the following:

    @inherits Umbraco.Web.Mvc.UmbracoViewPage<dynamic>
    @using Articulate;
    
    @{
    Layout = null;
    
    }
    

    My partial view is named Latest.cshtml and is located in App_Plugins/Articulate/Themese/MyTheme/Views/Partials directory. The partial view includes:

    @using Articulate
    @using Articulate.Models
    @inherits UmbracoViewPage<Articulate.Models.IMasterModel>
    
    @{
    var recent = Umbraco.GetRecentPosts(Model, 3);
    }
    
    <!-- Latest -->
    <div class="col-md-3 md-margin-bottom-40">
    <div class="posts">
        <div class="headline"><h2>Latest Posts</h2></div>
        <ul class="list-unstyled latest-list">
            @foreach (var post in recent)
            {
                <li>
                    <a href="@post.Url">@post.Name</a>
                    <small>
                        <time datetime="@post.PublishedDate">
                            @post.PublishedDate.ToString("MMM d, yyyy")
                        </time>
                    </small>
                </li>
            }
        </ul>
    </div>
    </div><!--/col-md-3-->
    <!-- End Latest -->
    

    I just want to call this view in my homepage...via @Html.ThemedPartial(Model, "Latest"), or @Html.Partial("Latest")...

    Any help would be really appreciated :)

  • Shannon Deminick 1524 posts 5269 karma points MVP 2x
    Feb 23, 2017 @ 23:25
    Shannon Deminick
    1

    Why is your home page Umbraco.Web.Mvc.UmbracoViewPage<dynamic>

    So what model type is it actually going to be??

    Your partial view expects a model of type IMasterModel because that is how you've declared it: UmbracoViewPage<Articulate.Models.IMasterModel>

    You haven't really explained the problem you are having, but I'll cross post the error you are getting from here: https://github.com/Shazwazza/Articulate/issues/218

    This standard MVC stuff, you are passing in the wrong model to your partial view and it seems you are trying to reference a type in the wrong namespace.

  • Bobi 346 posts 950 karma points
    Feb 24, 2017 @ 00:14
    Bobi
    0

    Sorry, my Homepage is:

    @inherits Umbraco.Web.Mvc.UmbracoTemplatePage<ContentModels.Index>
    @using ContentModels = Umbraco.Web.PublishedContentModels;
    @{
    Layout = "Master.cshtml";
    }
    
  • Kris Janssen 210 posts 569 karma points c-trib
    Feb 25, 2017 @ 19:16
    Kris Janssen
    1

    Just to chime in...

    I frequently integrate Articulate blogs in my site now and find it relatively easy to get e.g. 'recent posts' on the home page.

    There is a Master template:

    @inherits Umbraco.Web.Mvc.UmbracoTemplatePage
    @{
        Layout = null;
     }
    
     Html content goes here...
    

    My home page will look like this:

    @inherits Umbraco.Web.Mvc.UmbracoTemplatePage
    @using Umbraco.Web;
    ...
    
    @{
        Layout = "AG2Master.cshtml";
        ...
     }
    
    ...
    
    @Umbraco.Field("homePageNews")
    
    ...
    

    The Macro partial that interacts with the blog posts looks like this:

    @using Articulate
    @using Articulate.Models
    @using System.Linq
    ...
    @inherits Umbraco.Web.Macros.PartialViewMacroPage
    
    @{
        // Probably a bit inelegant but never bothered to improve this...
        var newsroot = Umbraco.TypedContentAtRoot()
                              .DescendantsOrSelf("Home")
                              .FirstOrDefault()
                              .DescendantsOrSelf("Articulate")
                              .FirstOrDefault();
        var blogArchive = newsroot.Children.First();
        var categories = Umbraco.TagQuery
                                .GetAllContentTags("ArticulateCategories")
                                .Select(x => x.Text)
                                .OrderBy(x => x);
        var categoriesUrl = newsroot.GetPropertyValue<string>("categoriesUrlName");
     }
    
     ...
     // You might want to e.g. group posts by categories
     @foreach (string c in categories)
     {
         var entries = blogArchive.Children
         //This ensures the latest is first
                .OrderByDescending(x => x.UpdateDate)
                //Get all latest items that has been tagged with a category of "Test" (case insensitive)
                // categories are stored as CSV so we split
                .Where(x => x.GetPropertyValue<string>("categories") != null && x.GetPropertyValue<string>("categories").Split(',').InvariantContains(c))
                .Take(3)
                .ToList();
    
         ...
    
         // A link to the category
         <h3><a href="@(newsroot.Url + "/" + categoriesUrl + "/" + c)">@c</a></h3>
         @foreach (var p in entries)
         {
             // It is possible to get crops of post images. Up to you to check that there is an image...
             var thumbnail = p.GetCropUrl("postImage", "frontPage");
             ...
    
             <p>@(Umbraco.Truncate(p.GetPropertyValue<string>("excerpt"), 75))</p>
    
             ...
          }
     }
    

    Note that I only kept the relevant parts, showing what can be achieved.

    Might not be the prettiest but it works

    EDIT

    Based on the comments, there were some obvious inefficiencies in the code above which I address below.

    @using Articulate
    @using Articulate.Models
    @using System.Linq
    ...
    @inherits Umbraco.Web.Macros.PartialViewMacroPage
    
    @{
        // EDIT: This node id is unlikely to ever change so hardcoding it should be OK.
        var newsroot = Umbraco.TypedContent(XXXX);
        var blogArchive = newsroot.Children.First();
        var categories = Umbraco.TagQuery
                                .GetAllContentTags("ArticulateCategories")
                                .Select(x => x.Text)
                                .OrderBy(x => x);
        var categoriesUrl = newsroot.GetPropertyValue<string>("categoriesUrlName");
    
        // EDIT: Get the Children here once instead of repeatedly
        var entries = blogArchive.Children();
     }
    
     ...
     // You might want to e.g. group posts by categories
     @foreach (string c in categories)
     {
         var filteredEntries = entries
                // EDIT: Splitting the property value is not needed ...
                .Where(x => x.GetPropertyValue<string>("categories") != null && x.GetPropertyValue<string>("categories").InvariantContains(c))
                //EDIT: Only order after selecting for the categories, less to order that way
                .OrderByDescending(x => x.UpdateDate)
                .Take(3)
                .ToList();
    
         ...
    
         // A link to the category
         <h3><a href="@(newsroot.Url + "/" + categoriesUrl + "/" + c)">@c</a></h3>
    
         //EDIT: only use the category filtered entries
         @foreach (var p in filteredEntries)
         {
             // It is possible to get crops of post images. Up to you to check that there is an image...
             var thumbnail = p.GetCropUrl("postImage", "frontPage");
             ...
    
             <p>@(Umbraco.Truncate(p.GetPropertyValue<string>("excerpt"), 75))</p>
    
             ...
          }
     }
    

    Is there more that can be done?

  • Bobi 346 posts 950 karma points
    Feb 26, 2017 @ 00:02
    Bobi
    0

    Thanks!

  • Kris Janssen 210 posts 569 karma points c-trib
    Feb 26, 2017 @ 08:56
    Kris Janssen
    0

    No Problem, let us know if you can get it to work...

    Also if the Shannon Deminick's of this forum have some feedback, feel free to post it. I have an inkling my code is not the most efficient :)

  • Shannon Deminick 1524 posts 5269 karma points MVP 2x
    Feb 26, 2017 @ 13:14
    Shannon Deminick
    1

    It will end up performing quite poorly if you get lots of blog posts on there, here's an important doc to understand querying and perf implications https://our.umbraco.org/Documentation/Reference/Common-Pitfalls/

  • Kris Janssen 210 posts 569 karma points c-trib
    Feb 26, 2017 @ 20:33
    Kris Janssen
    0

    Hi Shannon,

    I can see how my code will indeed be slow when there are lots of nodes. Re-arranging some of the calls might already help, as shown in the edits.

    Some other questions pop up when considering performance improvements. Would it be faster to:

    1. Get all the posts from the blog archive once using blogArchive.Children() and filter them for their category later on in a loop (as I am doing now)
    2. Get Umbraco.TagQuery.GetContentByTagGroup("ArticulateCategories"); once and next filter these for the specific category later on in a loop.
    3. Just run Umbraco.TagQuery.GetContentByTag(tag, "ArticulateCategories"); in a loop.

    I suspect option 1 would be the best: I already need one TagQuery call to get the list of Articulate specific tags:

    var categories = Umbraco.TagQuery
                            .GetAllContentTags("ArticulateCategories")
    

    This ultimately results in a DB call.

    If I would later on also get nodes using one of the TagQuery options (2 or 3), that would result in more DB calls.

    This whereas getting the Children for the blog archive and filtering them based on their categories property would not... Or am I wrong?

    So many questions ... :)

  • Bobi 346 posts 950 karma points
    Mar 03, 2017 @ 20:17
    Bobi
    0

    Hi Kris,

    I'm getting all types of errors with the edit.

    var newsroot = Umbraco.TypedContent(XXXX);
    

    'The name XXXX does not exist in the current context.'

    var blogArchive = newsroot.Children.First();
    

    'PublishedContentExtensions.Children(IPublishedContent)' is a method, which is not valid in the given context'

    <h3><a href="@(newsroot.Url + "/" + categoriesUrl + "/" + c)">@c</a></h3>
    

    'Operator '+' cannot be applied to operands of type 'method group' and 'string''

    @foreach (var p in filteredEntries)
    

    '"foreach" keyword after "@" character. Once inside code, you do not need to prefix constructs like "foreach" with "@".'

  • Kris Janssen 210 posts 569 karma points c-trib
    Mar 03, 2017 @ 22:25
    Kris Janssen
    1

    Hi Bobi,

    You cannot just copy the code literally.

    'XXXX' obviously needs to be replaced by the specific node ID of your articulate blog.

    All the other errors are most likely also related to the fact that I omitted all custom parts in the razor code to show only the important bits. If you copy things literally, the succession of pure html vs Razor code is probably getting mixed up. Everywhere where there are '...' there was actually some html (which was irrelevant to demonstrate the concepts used.

    If you are a bit confused by this, perhaps first grab a good Razor tutorial from the web.

  • Bobi 346 posts 950 karma points
    Mar 03, 2017 @ 23:07
    Bobi
    0

    I see, thanks. If you want to get only one category, say "test" category, how would the code be manipulated? I am trying to just display the "test" category, but also, if there are no "test" categories, then display some generic html code (i.e. <p> No recent news</p>).

  • Bobi 346 posts 950 karma points
    Mar 04, 2017 @ 21:15
    Bobi
    0

    Ok, I have played around with everything, and seem to have it working.

    Perhaps there are some inefficiencies in the code, but nevertheless:

    @using Articulate
    @using Articulate.Models
    @using System.Linq
    
    @inherits UmbracoTemplatePage
    
    @{
    // EDIT: This node id is unlikely to ever change so hardcoding it should be OK.
    var newsroot = Umbraco.TypedContent(1066);
    var blogArchive = newsroot.Children.First();
    var categories = Umbraco.TagQuery
                            .GetAllContentTags("ArticulateCategories")
                            .Select(x => x.Text)
                            .OrderBy(x => x);
    var categoriesUrl = newsroot.GetPropertyValue<string>("categoriesUrlName");
    
    // EDIT: Get the Children here once instead of repeatedly
    var entries = blogArchive.Children();
    
    var filteredEntries = entries
                       // EDIT: Splitting the property value is not needed ...
                       .Where(x => x.GetPropertyValue<string>("categories") != null && x.GetPropertyValue<string>("categories").InvariantContains("Test"))
                       //EDIT: Only order after selecting for the categories, less to order that way
                       .OrderByDescending(x => x.CreateDate)
                       .Take(3)
                       .ToList();
    }
    
    <!--=== News Block ===-->
    <div class="bg-grey">
    <div class="container content-sm">
        <div class="text-center margin-bottom-50">
            <h2 class="title-v2 title-center">RECENT NEWS</h2>
        </div>
        <div class="row news-v1">
    
    
            @if (filteredEntries == null || filteredEntries.Count() == 0)
            {
                <div class="md-margin-bottom-40 text-center">
                        <h3 class="font-normal">No Recent News</h3>
                </div>
            }
            else
            {
                foreach (var blogNode in filteredEntries)
                {
                    var blogTitle = @blogNode.Name;
                    var tempExcerpt = @blogNode.GetPropertyValue("excerpt").ToString();
                    var postDate = blogNode.CreateDate.ToString("MMMM d, yyyy");
                    const int MaxLength = 133;
    
                    <div class="col-md-4 md-margin-bottom-40">
                        <div class="news-v1-in bg-color-white">
                            <a href="@blogNode.Url"><img class="img-responsive" src="@blogNode.GetCropUrl("postImage", "indexBlogPost")" title="@blogTitle" alt="@blogTitle" /></a>
                            <h3 class="font-normal"><a href="@blogNode.Url">@blogTitle</a></h3>
                            @if (tempExcerpt.Length > MaxLength)
                            {
                                tempExcerpt = tempExcerpt.Substring(0, MaxLength) + "...";
                            }
                            <p>@tempExcerpt</p>
                            <ul class="list-inline news-v1-info no-margin-bottom">
                                <li><i class="fa fa-clock-o"></i> @postDate</li>
                            </ul>
                        </div>
                    </div>
                }
            }
        </div>
    </div>
    </div>
    <!--=== End News Block ===-->
    

    Here, I am trying to find all Categories named "Test" and display them. If they are no categories, then "No recent News" is displayed.

  • Matt Taylor 873 posts 2086 karma points
    Feb 18, 2021 @ 15:02
    Matt Taylor
    0

    I have complex permutation that I don't think has been covered here yet.

    My Umbraco v8 project is an upgraded/hacked version of Jeroen Breuer's Hybrid Framework for Umbraco v7 project.

    In my project, just like the Articulate project every page's route is hijacked through it's own controller which returns a master model, ViewModels.IMasterModel.

    This ViewModels.IMasterModel master model contains all the properties I need to use at a global level across all the website's pages and is used as the model for my master base view:

    @inherits Umbraco.Web.Mvc.UmbracoViewPage<IMasterModel>
    

    My master base view then sets all the global properties, like meta data.

    Articulate is exactly the same from what I can see. It has its own master model, Articulate.Models.IMasterModel which contains it's own properties and is used in the Articulate theme's Master view.

    Both the my ViewModels.IMasterModel and Articulate.Models.IMasterModel inherit IPublishedContent.

    Although Articulate does it on the Interface:

    public interface IMasterModel : IPublishedContent
    

    and my project does it on the class:

    public class MasterModel<T> : ContentModel<T>, IMasterModel
            where T : class, IPublishedContent
    

    How can I sort of merge these two master models so that I can continue to use my ViewModels.IMasterModel in my master base view which has all the site's styling and inherit it from the Articulate theme's views?

  • Matt Taylor 873 posts 2086 karma points
    Feb 19, 2021 @ 13:25
  • Matt Taylor 873 posts 2086 karma points
    Feb 19, 2021 @ 17:58
    Matt Taylor
    0

    Now that I have managed to integrate the views with my own by changing the model I'm finding that some of the Html helper methods are not working.

    @Html.ThemedPartial(articulateModel, "PostTags") 
    

    will error so I have to use

    @Html.Partial("~/App_Plugins/Articulate/Themes/MySite/Views/Partials/PostTags.cshtml", articulateModel)
    

    @Html.RenderOpenSearch(Model) will display nothing so I have to use @Html.Partial("~/App_Plugins/Articulate/Themes/MySite/Views/Partials/SearchBox.cshtml", articulateModel)

    I think it's getting confused now that the model is different.

    Is there a way to explicitly call the Articulate helpers?

    Thanks,

    Matt

Please Sign in or register to post replies

Write your reply to:

Draft