Sidebar Summary using Visualforce

About a year ago, I posted about the Sidebar Summary.  The Sidebar Summary exists in the sidebar and displays the counts of some important queries.  The counts are also hyperlinks to a view or report representing that query.  It’s a very handy thing to have in your sidebar and I use it all the time for my own work.  However, because it’s an s-Control, it runs a little slow.  In fact, it ran slow enough to make me uncheck the user interface option “Show Custom Sidebar Components on All Pages”.

I changed it into a Visualforce page with a custom Apex controller and now it runs super fast and I am able to keep the “Show Custom Sidebar Components on All Pages” option turned on and see it on every page I go to.  There’s a bit of hardcoding in here, but it gets the job done pretty well.  Bye bye s-Control.


The Page is almost all raw HTML.  The only dynamic thing in there are the count values.  Each one retrieves the value from a specific “get” method in the controller.  If you like the queries I use, then the only thing you’ll need to confirm are the URLs that get linked to.  The first 2 go to Views in my Org and the last 2 go to Reports in my Org.  You’ll need to change those URLs.

I named the VF Page “SidebarSummary”.

<apex:page controller="VFController_Sidebar_Summary" sidebar="false" showHeader="false" standardStylesheets="true">
<style type="text/css" media="all">
body{margin: 0; padding: 0; color: #000000; background-color: #E8E8E8;}
#DIV_Container {background-color: #F3F3EC;}
<div id="DIV_Container">
<tr><td><em>Unread Leads</em>:  </td><td><a href="/00Q?fcf=00B30000005JhsT" target="_parent"><b>{!UnreadLeads}</b></a></td></tr>
<tr><td><em>Leads - Not Contacted</em>:  </td><td><a href="/00Q?fcf=00B30000005Jhru" target="_parent"><b>{!NotContactedLeads}</b></a></td></tr>
<tr><td><em>Oppty - Next 30 Days</em>:  </td><td><a href="/00O30000001aEHV" target="_parent"><b>{!Next30DayOppty}</b></a></td></tr>
<tr><td><em>Oppty - Past Due</em>:  </td><td><a href="/00O30000001aEHV" target="_parent"><b>{!PastDueOppty}</b></a></td></tr>


The controller has a method for each query to be run.  Each query is a count() query and returns an Integer.  At the end is a really lame Test method, but it does get 100% of the code covered.  I am certain the code works, so I didn’t do too much with the Test method.  Salesforce just requires the code to be tested.

public class VFController_Sidebar_Summary {

public Integer getUnreadLeads() {
return [
select count() from Lead
where IsConverted = False
AND IsUnreadByOwner = TRUE

public Integer getNotContactedLeads() {
return [
select count() from Lead
where IsConverted = False
AND Status = 'Open - Not Contacted'

public Integer getNext30DayOppty() {
return [
select count() from Opportunity
where IsClosed = False
AND (CloseDate = Next_N_DAYS:30 OR CloseDate = TODAY)

public Integer getPastDueOppty() {
return [
select count() from Opportunity
where IsClosed = False
AND CloseDate < TODAY

static testMethod void testVFController_Sidebar_Summary() {
Test.setCurrentPageReference(new PageReference('Page.SidebarSummary'));
VFController_Sidebar_Summary controller = new VFController_Sidebar_Summary();
Integer i1 = controller.getUnreadLeads();
Integer i2 = controller.getNotContactedLeads();
Integer i3 = controller.getNext30DayOppty();
Integer i4 = controller.getPastDueOppty();



<span style="text-decoration: underline;"><strong>Homepage HTML Component</strong></span>

I created a component for the Narrow side and put the following HTML into the editor.  Essentially, you create an IFRAME and embed the VF page into it.  I found a (unsupported) trick on the forums to remove the developer bar from a page.  Just add <strong>?core.apexpages.devmode.url=1</strong> to the URL.  This will turn off development mode when that page is rendered.  This is important for this little iFrame page on the sidebar.  From what I've gathered, this hack is not supported and could change at any time.

The code below should work for you.  The only thing you might need to change is the Page URL if you didn't name your page SidebarSummary and the height of it.

<iframe src="/apex/SidebarSummary?core.apexpages.devmode.url=1" frameborder="0" height="100" width="100%"></iframe>

Let me know what you think.


  1. David Schach Said,

    September 19, 2008 @ 11:27 am

    This is a SUPER post with exactly the kind of project that we should all be working on: Taking existing solutions and improving them, and then taking the lessons we learn from those to craft solutions to new challenges. Great job, and great code. Question: Can we use the CurrentPage variable to get around the need to test ‘Page.SidebarSummary’?
    Regarding the iframe usage, you have used it well, but I would offer these words of caution: Your solution here works because your data is of a constant number of rows. Unfortunately, I’ve not found a way to create homepage components with dynamic height features, so lists are still not an option. (And yes, I tried all the AJAX I could find, but passing values from the frame to the homepage seems impossible.
    That said, SUPER job – I really like the streamlined way you used SOQL to generate an integer which was simply passed to the page, and your test code is clear and effective.
    Thanks, Scott!

  2. CK Said,

    September 19, 2008 @ 2:29 pm

    Hi, good stuff….
    I have a question on the URL for the views…. with the “enhanced list view” feature enabled, there is no way to get a URL for a list view, any solution?

  3. Scott Hemmeter Said,

    September 20, 2008 @ 8:34 am

    @CK: Well, I actually had the URLs in there already from last year and I now used Enhanced Views and it all worked. Maybe you can turn off Enhanced Lists, get the URLs and then turn them back on?

  4. Rhonda Ross Said,

    September 20, 2008 @ 4:14 pm

    If you go to the list view and click edit, it will show you the ID that you need within the URL – even with enhanced list views.

  5. Rhonda Ross Said,

    September 20, 2008 @ 5:12 pm


    This is so cool! I can’t wait to add this to my production org. But, to do that need help with one item. In your s-control version, you included some code so that the queries would show just the records owned by the logged in user. Is that same functionality possibility with the Visualforce version, and if so, how?

  6. Scott Hemmeter Said,

    September 21, 2008 @ 8:13 pm

    @Rhonda, you can add the following to your query:

    AND OwnerId = :UserInfo.getUserId()

  7. CK Said,

    October 3, 2008 @ 7:09 am

    @ Rhonda Ross: you cannot get the unique URL for the enhanced list views, if you tog between different views, you will notice the URL does not change.

  8. Scott Hemmeter Said,

    October 3, 2008 @ 9:10 am

    Well, this isn’t ideal, but the following appears to work…

    Your URL will be “/prefix?fcf=viewID. For example, for a Lead view, it will look like: /00Q?fcf=00B30000005JhsT. The prefix is the 3 letter prefix assigned to that object.

    Start by going to any view for the object you care about and copy that URL somwhere. Then go to the View you want to link to. Once there, right-click on the Edit link and copy the URL. Use the ID from that copied URL and replace it in the main URL you are putting into your code.

    Ugly, but should work.

  9. CK Said,

    October 3, 2008 @ 10:25 am

    Thanks, I linked the ## to reports, not views.
    It is indeed much faster than the S control version.

    Is it possible to set the font size in the summary section? Mine shows 2 lines for some rows like “Oppty Closing This Month”.

  10. Scott Hemmeter Said,

    October 3, 2008 @ 11:06 am

    @CK, yes you can change font-size with CSS. In my example, there’s a section that says:

    #DIV_Container {background-color: #F3F3EC;}

    You want to add a font-size option. The value can be a specific size (e.g. 6pt) or a relative size to the standard (e.g. .8em). Example below:

    #DIV_Container {background-color: #F3F3EC; font-size: .9em;}

  11. CK Said,

    October 3, 2008 @ 1:33 pm

    Thank you, Scott.
    I changed the font and now it looks beautiful.

  12. CK Said,

    October 4, 2008 @ 9:51 pm

    adding the “with sharing” property in the public class is good in some case because the managers should see his team’s opps, if the sharing default is private.

    @Rhonda, you can add the following to your query:

    AND OwnerId = :UserInfo.getUserId()

  13. Marc B Said,

    October 10, 2008 @ 8:37 am


    super useful and can’t wait to try out in my org. Thanks for this post – terrific!


  14. CK Said,

    December 14, 2008 @ 11:11 am

    This has been working well…. but however, when I click “run test” on the class today, it say test failed:

    Test Class VFController_Sidebar_Summary
    Tests Run 1
    Test Failures 1
    Code coverage total % 100
    Total time (ms) 0

    Class VFController_Sidebar_Summary testVFController_Sidebar_Summary 136 System.Exception: Too many query rows: 501 Class.VFController_Sidebar_Summary.getPastDueOppty: line 52, column 8
    Class.VFController_Sidebar_Summary.testVFController_Sidebar_Summary: line 68, column 14

    And I cannot deploy other class even the “package.xml” file does not list this class, it gives me same error.

    Any idea why?


  15. CK Said,

    December 14, 2008 @ 11:45 am

    The above error is in my production, but when I run the test in developer edition, it works and no failure.

  16. Scott Hemmeter Said,

    December 15, 2008 @ 11:41 am


    The error is due to one of you queries having more than 1000 rows. It’s a limitation I didn’t realize when writing the post. Only workaround I have is to remove the query counting that many rows or to put a limit on the query of 1000 (put “LIMIT 1000” at the end of the SOQL statement). You will just have to train people that if they see 1000, it means “1000+”.

  17. Per Geert Said,

    December 24, 2008 @ 8:49 am


    Actually the error is only in your test method (if your are below 10,000 records). A way around this is to find a way the test method returns fewer than 500 rows, e.g. by using System.runAs(some user user).

  18. Tom Said,

    July 14, 2009 @ 9:21 am

    Hi, I’ve got this iframe idea working fine in IE, but Firefox gives a Redirect Loop error “Redirection limit for this URL exceeded. Unable to load the requested page. This may be caused by cookies that are blocked.”
    I’m just pointing the iframe at an apex page. Did anyone else encounter this issue with Firefox, and if so how did you fix it?

  19. Brendan Said,

    June 24, 2010 @ 6:38 pm

    Good work Scott,

    I have completed the above and all works well for me in my sandbox (i am an administrator). However when i view the sidebar summary via a login that is not an administrator, it is displaying the homepage within the small box, not the list of results required.

    Please help.


  20. Scott Hemmeter Said,

    June 25, 2010 @ 7:29 am

    @Brendan, Go to the page you have embedded in the Setup and make sure its security is assigned to all your profiles. Most likely, what those users are seeing is a message that says they do not have the rights to the page.

  21. Kevin Edelmann Said,

    August 4, 2010 @ 12:33 pm

    This works great when you are counting, is there a way to sum items instead? I ask as I am new to the Apex world and I tried using sum instead and I get an error. Any help wold be greatly appreciated.


  22. Scott Hemmeter Said,

    August 4, 2010 @ 2:45 pm

    @Kevin, you want to look at Aggregate Functions

  23. Manoj Said,

    May 3, 2011 @ 4:44 am

    Hi Scott,

    The code works great, but I have been trying to get the sum (Amount) of the opportunities and I’ve been hitting my head for the past two days and not able to get the solution, I also tried to help from your link for Aggregate Functions but not able to get the tail of it.

    I’ve never worked on Apex/Visualforce before and don know where the problem is,can you please help me in this.

  24. Ray Said,

    November 21, 2011 @ 6:09 pm

    Thanks for the code. Is there a way to make the counts show leads and opportunities that are owner by the current user?

RSS feed for comments on this post