Fine-Grain SEO Controls for CS 2008?

Fine-Grain SEO Controls for CS 2008?

  • I was wondering if Community Server will include any functionality for more fine-grained SEO control. Specifically, will there be any support for being able to edit META keywords and descriptions on each published page?

    The site-wide meta keyword controls that are in place right now aren't particularly useful given that subject mater can vary significantly in each blog post or forum thread. WordPress has several seo plugins (All in One SEO is the one I use) that allow me to do this for WP, but will I ever see anything like that in future releases of Community Server?

  • I've done this at a very basic level on my website by adding some code to the Master.master page (~/Themes/YOUR THEME/Common/Master.master) to do some basic manipulation of Meta tags based on the current page - e.g. if we're viewing the post, add the post's excerpt as the description, and any post tags as the Keywords, if you're viewing a specific section [e.g. blog, forum etc.), add the section's description as a Meta Description.

    The comments in the code below should help show what senarios are handles.

    <script runat="server" type="text/C#">

        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            //SEO Stuff

            CSContext cscontext = CSContext.Current;

            // If we're in a forum Thread, add the description of the first post in the thread as
            // the Meta Description, and keywords of that post as Meta Keywords
            if (cscontext.ThreadID > 0 && cscontext.ApplicationType == ApplicationType.Forum)
            {
                CommunityServer.Discussions.Components.Thread t = CommunityServer.Discussions.Controls.ForumControlUtility.Instance().GetCurrentThread(this);

                if (t != null)
                {
                    Head.AddMetaDescription(t.ForceExcerpt, cscontext.Context);

                    if (t.Categories != null)
                    {
                        Head.AddMetaKeywords(String.Concat(t.Categories), cscontext.Context);
                    }
                }
            }

            // If we have a specific post, add the post excerpt as the Meta Description
            // and if the post has any tags, add those as Meta Keywords
            else if (cscontext.PostID > 0 || !String.IsNullOrEmpty(cscontext.PostName))
            {
                Post p = CSControlUtility.Instance().GetCurrentPost(this.Page);

                if (p != null)
                {
                    Head.AddMetaDescription(p.ForceExcerpt, cscontext.Context);

                    if (p.Categories != null)
                    {
                        Head.AddMetaKeywords(String.Concat(p.Categories), cscontext.Context);
                    }
                }
            }
            //If we don't have a post, do we have a Section
            else if (cscontext.SectionID > 0)
            {
                Section section = CSControlUtility.Instance().GetCurrentSection(this.Page);

                //Add Section Description as Meta Description
                Head.AddMetaDescription(section.Description, cscontext.Context);
            }

            // Are we in a Section Group, add the group description as the Meta Description
            //N.b. Groups as in Forum Groups, Blog Groups as opposed to Hubs
            else if (cscontext.GroupID > 0)
            {
                CommunityServer.Components.Group group = CSControlUtility.Instance().GetCurrentGroup(this.Page);

                if (group != null && !String.IsNullOrEmpty(group.Description))
                    Head.AddMetaDescription(Formatter.RemoveHtml(group.Description, 250), cscontext.Context);
            }

            // If we're on a user profile page, put the User Bio as the Meta Description
            else if (!string.IsNullOrEmpty(cscontext.UserName) || cscontext.UserID > 0)
            {
                User u = CSControlUtility.Instance().GetCurrentUser(this);

                if (u != null && !String.IsNullOrEmpty(u.Profile.Bio))
                    Head.AddMetaDescription(Formatter.RemoveHtml(u.Profile.Bio, 250), cscontext.Context);
            }

            // If we are on a Tags page, add tags as Meta Keywords
            // We might be on a tags page in a specific section, so don't use ELSE on if statement
            if (cscontext.Tags != null)
            {
                Head.AddMetaKeywords(String.Concat(cscontext.Tags), cscontext.Context);
            }
        }

    </script>

  • I agree that we need better control over the meta data.  I wouldn't think the it would take to much to add two meta data fields when creating a new forum or blog.

     

  • Hello Alex,

    i have one question about this approach. You are using these:

    cscontext.PostID
    cscontext.PostName
    cscontext.ThreadID
    cscontext.GroupID
    ...

    To determine where in the community you are. But my problem is - i do not have these properties on cscontext object? Is this changed in newest CS? Im using rewritten urls to determine this - and currently this is completely ok. But i would like to have more control over it. What do you think about this?

  • I went through this just yesterday.  Those IDs are no longer available on the context object, but what I did was use cscontext.GetCurrent<Item>() != null instead of cscontext.ItemID > 0.  Replacing Item with the right thing - Post, Thread, Section, Group, etc.  It seems to work pretty well with that change.

    --
    --Jeff (ATGi)
  • Jeff

    Could you post the full modifications you made?

  • Jeff,
    thanks for fast answer...This approach is very elegant.

    I realized i can maybe use this approach - but considering that im newbie in cs and fact that going through rewritten urls is completely ok for our situation (we need page by page control) - i implemented catching pages by rewritten url....

  • Here is the code that I used, or a rough approximation of it, as there were a couple bits I had to change.

        
        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            //SEO Stuff
    
            CSContext cscontext = CSContext.Current;
    
            // If we're in a forum Thread, add the description of the first post in the thread as
            // the Meta Description, and keywords of that post as Meta Keywords
            if (cscontext.ApplicationType == ApplicationType.Forum
                && cscontext.GetCurrent<CommunityServer.Discussions.Components.Thread>() != null)
            {
                CommunityServer.Discussions.Components.Thread t = cscontext.GetCurrent<CommunityServer.Discussions.Components.Thread>();
    
                Head.AddMetaDescription(t.ForceExcerpt, cscontext.Context);
                if (t.Categories != null)
                    Head.AddMetaKeywords(String.Concat(t.Categories), cscontext.Context);
            }
    
            // If we have a specific post, add the post excerpt as the Meta Description
            // and if the post has any tags, add those as Meta Keywords
            else if (cscontext.GetCurrent<Post>() != null)
            {
                Post p = cscontext.GetCurrent<Post>();
                Head.AddMetaDescription(p.ForceExcerpt, cscontext.Context);
    
                if (p.Categories != null)
                    Head.AddMetaKeywords(String.Concat(p.Categories), cscontext.Context);
            }
            //If we don't have a post, do we have a Section
            else if (cscontext.GetCurrent<Section>() != null)
            {
                Section section = cscontext.GetCurrent<Section>();
    
                //Add Section Description as Meta Description
                Head.AddMetaDescription(section.Description, cscontext.Context);
            }
    
            // Are we in a Section Group, add the group description as the Meta Description
            //N.b. Groups as in Forum Groups, Blog Groups as opposed to Hubs
            else if (cscontext.GetCurrent<CommunityServer.Components.Group>() != null)
            {
                CommunityServer.Components.Group group = cscontext.GetCurrent<CommunityServer.Components.Group>();
    
                if (group != null && !String.IsNullOrEmpty(group.Description))
                    Head.AddMetaDescription(Formatter.RemoveHtml(group.Description, 250), cscontext.Context);
            }
    
            // If we're on a user profile page, put the User Bio as the Meta Description
            else if (cscontext.RewrittenUrlName.Equals("user_ByUserName"))
            {
                User u = cscontext.User;
    
                if (u != null && !String.IsNullOrEmpty(u.Profile.Bio))
                    Head.AddMetaDescription(Formatter.RemoveHtml(u.Profile.Bio, 250), cscontext.Context);
            }
    
            // If we are on a Tags page, add tags as Meta Keywords
            // We might be on a tags page in a specific section, so don't use ELSE on if statement
            if (cscontext.Tags != null)
            {
                Head.AddMetaKeywords(String.Concat(cscontext.Tags), cscontext.Context);
            }
        }
    
    
    --
    --Jeff (ATGi)
  • bojan

    I realized i can maybe use this approach - but considering that im newbie in cs and fact that going through rewritten urls is completely ok for our situation (we need page by page control) - i implemented catching pages by rewritten url....

    If you need page by page control then I would say that following this pattern, but catching them by rewritten url is the right solution if you are a newbie or an long time CS dev.

    --
    --Jeff (ATGi)
  • Hi Jeff,

    Great stuff!

    I'm just getting an error when I try to implement it:

    Compilation Error

    Description: An error occurred during the compilation of a resource required to service this request. Please review the following specific error details and modify your source code appropriately.

    Compiler Error Message: CS0246: The type or namespace name 'CSContext' could not be found (are you missing a using directive or an assembly reference?)

    Source Error:

    Line 15:         //SEO Stuff
    Line 16: 
    Line 17:         CSContext cscontext = CSContext.Current;
    Line 18: 
    Line 19:         // If we're in a forum Thread, add the description of the first post in the thread as

    Can you tell me what's wrong?

  • You need a:

    <%

    @ Import Namespace="CommunityServer.Components" %>

    in your file.

    --
    --Jeff (ATGi)
  • Hi Jeff,

    Thank you that helped! Smile

  • Hi Jeff,

    I just want to thank you one more time for this post. Smile

    Of course I'm not 100% sure, but I can see that I'm getting more and more hits from Google after this change. And that's in only 2 weeks. And of course I also have less and less "errors" in Googles Webmaster tools pages with identical meta descriptions. But it takes some time for google to index all my pages (100000+).

  • Glad to hear that things seem to be perking up a bit in terms of traffic. Alex deserves most of the credit here as he did the intial hard work. I just came along and did a bit of an update based on some API changes in Community Server and tweaked a couple small things.

    --
    --Jeff (ATGi)
  • Sorry if this is a stupid question but where do I put this code? Do I need to create a .cs page for the master.Master.aspx file and place it there?