TwentyTen CRM

This theme is here for archival purposes only. My CRM that’s actively developed is Genesis CRM.

Download the theme on GitHub

by Bill Erickson, Andrew Norcross, Jared Atchison


TwentyTen CRM is a child theme for TwentyTen specifically designed as a Customer Relationship Management tool. It creates a series of taxonomies and custom meta boxes to collect relevant data, displays the data in a useful Dashboard page template, features a Download page template that can be used to copy/paste all the data to Excel for more advanced analysis, and is easily customized to your specific needs. Oh, and it’s free.


About six months ago I started to become overwhelmed by the number of prospective client inquiries I received. It’s a great problem to have, but a lot of prospects were falling through the cracks. I tried Salesforce for about a week, and SugarCRM for about 3 weeks (I must thank Schipul for spending an afternoon walking me through how their company manages their contacts with Sugar).

The two problems I had with all of these CRMs were that it was difficult to put the information I wanted in the system (and leave out the information I didn’t care about), and it was difficult to analyze that data. I wanted a tool that I could customize to my own needs and modify as time went on. As a WordPress developer, I chose the tool I’m most comfortable with.

This theme isn’t perfect for everyone, but it can easily be customized to your specific needs using standard WordPress code, which is exactly what I wanted. I recommend you see this as a starting point, not an end point.


First, due to the type of content we’re putting in this site, I highly recommend you either run it locally, or use a plugin like Registered Users Only to ensure it isn’t public.

  1. Download the theme
  2. Add it to your themes directory and activate. Since it is a child theme of TwentyTen, you must have TwentyTen in your themes directory as well.
  3. I recommend you fill in the Categories, Points of Contact, and Sources taxonomies first.
    1. Categories must contain Prospect (slug “prospect”), Active Project (slug “active-project”) and Closed (slug “closed”) to function correctly. Alternatively  you could modify the theme files to use different categories for the sections of the Dashboard.
    2. I use Point of Contact as the method the client initially contacted me (Email form, Email, Phone…). I’d recommend you only use one POC per project as it will mess up the stats in the dashboard if you use multiple.
    3. I use Sources as the person or website that sent the prospect to me. Mine include CodePoet, StudioPress, DIYThemes, Google, Other Referral (you can specify the Other Referral in the custom meta boxes), Unknown…
  4. Go to Appearances > Widgets and populate the three homepage widget areas with widgets. I recommend “Old Prospects” in Column 1, “Active Projects” in Column 2, and everything else in Column 3.
  5. Start collecting data! Just go to Posts > Add New to add a new prospect.


While my default setup might work fine for you, one of the best features of this theme (and WordPress in general) is how easy you can customize it.

There’s two features you should attempt customizing: Taxonomies and Custom Meta Boxes. Note: I’m assuming you are a web developer and are already comfortable coding these types of things. If not, you might want to hire someone to do it.

Taxonomies – Go to twentyten-crm/functions.php. On line 93 you see // Register Taxonomies. This is the code I’m using to create the taxonomies. You can modify the two default taxonomies here, or create additional ones. See the Codex for more information. And of course you can add additional taxonomy terms using the appropriate section of the backend (ex: Posts > Sources).

Custom Meta Boxes – I’m using a wonderful piece of code that Andrew Norcross recently contributed to generate the meta boxes. To see all the meta box options you have, go to /twentyten-crm/lib/metabox/example-functions.php. To modify the existing metaboxes or add more, go to /twentyten-crm/functions.php on line 165.

Once you’ve modified the data you collect on the backend, you’ll want to modify the frontend display of that data. Here’s the three files you should edit:

  • home.php – This is the Dashboard page template.
  • download.php – This is the Download page template.
  • single.php – This is the Single page template

Looking through the code on those pages, you should be able to figure out how to add what you want.

More Customization Tips

  • We’ve added a “Top Panel” to the top that gives you two menus, both editable from Appearance > Menus. If you’d like to replace this with the admin bar (assuming you’re running WP 3.1), uncomment lines 523-525 (look for “Top Panel instead of Admin Bar”).
  • The post editor has been moved into a meta box so you can drag it around and put it wherever you like. If you don’t want to use it, click Screen Options and uncheck “Notes”.
  • I’ve created a bunch of useful widgets for the homepage. If you’d like to create your own, just put them in the /lib/widgets folder. I also added two hooks that some of the widgets use: crm_pre_stat_loop and crm_stat_loop. This loop goes through all the posts in the site and is used to calculate statistics. If your widget needs to loop through them as well, I’d recommend using this instead of doing your own loop in your widget. This way there’s only one loop rather than one for each widget. Look into a widget like widget-other-stats.php for an example on how to use this.


  • 1.3 (2/21/11) A large release with many changes. Here’s a few notable ones:
    • Made the dashboard the homepage (so you don’t need to create a page, set page template, then set as homepage). Widgetized the homepage so you can control what boxes show up where.
    • Lots of tweaks to the backend. Moved post editor into meta box, renamed “Post” to “Contact”, reordered/removed admin menu items, removed dashboard widgets (will create some in a future release), and customized the Contacts column view to include Status, Point of Contact, and Source.
    • Cleaned up the code so it runs better. It should work with debug mode on now! (Thanks Mark Jaquith for the tips)
  • 1.2 (2/5/11)
    • Added isset() to variables in /metabox/init.php and improved method of hiding post editor, based on recommendations by Mark Jaquith
    • Used global variable $prefix to be used in generating custom fields in meta box as well as in the page templates. If you want to use a different prefix, change it once without editing a bunch of files.
  • 1.1 (2/3/11) – Updated the metabox code based on improvements by Jared Atchinson
  • 1.0 (1/31/11) – Initial release

Bill Erickson

Bill Erickson is a freelance WordPress developer and a contributing developer to the Genesis framework. For the past 14 years he has worked with attorneys, publishers, corporations, and non-profits, building custom websites tailored to their needs and goals.

Ready to upgrade your website?

I build custom WordPress websites that look great and are easy to manage.

Let's Talk

Reader Interactions


  1. Todd J. List says

    One of the things I love about the WordPress community is their willingness to share something awesome.

    This looks like a great resource, not only as a tool, but also as a great way for a new developer (like me) to get more comfortable with some of the more powerful pieces of WordPress.

    Thank you.

  2. Marty Thornley says

    Hey Bill,
    Great work! Love the dashboard page but the download page is my favorite aspect so far… I just copy and pasted perfectly right into a Google Doc spreadsheet! Very cool!
    Can’t wait to play with it some more.

    • Bill Erickson says

      Glad you like it! Wait until you see v1.3 coming out this weekend (hopefully). The dashboard is fully widgetized, so you can arrange it however you like and add/remove all the components.

  3. Miijiik says

    thanks for gorgeous and useful theme.

    I just found a little display bug; Client information and Project info wasn’t displayed on single page (on my xampp installation), so I was fiddling around and found out that in single.php, you are calling custom fields this way (which didn’t display anything for me):

    $email = get_custom_field('crm_client_email');

    When I fixed this to be called same way as in download.php template, all is working ok:

    $email = get_custom_field($prefix.'client_email');

    Keep up cool work, and thanks again for this splendid example of using WP.

    • Bill Erickson says

      Not yet. I need to create a bunch of dummy content for a demo to be useful. Right now I’m using actual client data and don’t want it to be public.

  4. Christine Green says

    This is amazing! I’ve been struggling with the same issues trying to find a CRM that fit my needs. Thanks so much for creating this free CRM theme!

  5. Sakib says

    I would like to give a BIG hugs and thanks. Amazing share, wordpress created a platform, where people love to share their knowledge, experiences and as well cool works with entire world. Thanks so much bill, great creation.

  6. Kate Mag says

    Do you have a plan to put the TwentyTenCRM theme to repository?
    I liked this idea, the theme looks awesome. Thanks for sharing this theme

    • Bill Erickson says

      I’ve actually spoken with Otto about this (one of the reviewers) and I’d love to get it in there. I originally submitted it to the repo before posting it on here, but it didn’t make it because it was a child theme. Otto said he could get it around that, but we’re trying to decide if we want to continue building it off of TwentyTen or make it a standalone theme.

      So yes, we should have it in the repo soon, but we need to figure out how best to approach it.

      • Matthew McGarity says

        My preference would be for this to be stand-alone — that way, one is not dependent on the parent theme being there, being updated, not having issues, etc.

        Good work!

  7. RIch says

    Hey mate awesome job.

    Any chance of writing a outlook csv contact import script?
    Also, I am collecting date from my site in terms of applicants for jobs, and bookings for events, with two seperate plugins for each purpose.
    I suppose intergating that data into TwentyTenCRM would not be an easy task…?

    • Bill Erickson says

      There’s no plans of writing an outlook contact importer, but if you (or a developer you hire) build one as a plugin I’d be happy to promote it here.

      I don’t think it would be too difficult to collect that type of data with TwentyTen CRM. Here’s some approaches, in increasing difficulty:
      – Set up two independent installs of TwentyTen CRM. This gives you the ability to collect the relevant data for each contact type and analyze it.
      – Set up one install and add a taxonomy “Interest” (or something similar) with the terms “job applicant” and “event booking”. The downside to this is all the widgets will display aggregate data of both, so I’m not sure how useful it would be.
      – Change the “Contacts” label to “Applicants” and create a post type called “Event Bookings”. You can then create relevant meta boxes for each, to collect the data you want. You would also need to modify all the widgets, possibly adding a “post type” option to select what data source to use. You could then have two of every widget – one for each post type.

  8. Andrew says

    Bill or anyone, not sure if this is the right place but I think I missed a setup step. If I open the panel and go to “Active” or “Prospects” it gives me a 404 trying to get to /twentytencrm/prospects/ for example. Is there a page or post I should setup with some shortcode?

    Thanks for such a cool theme and great idea!

    • Bill Erickson says

      Good catch. I think Andrew Norcoss had those pages in his install and hardcoded it that way. Basically both menus in the top panel are WordPress menus, editable from Appearance > Menus. If you don’t create any menus, there’s a fallback menu in functions.php on line 22 that has those links hardcoded. In the next version I’ll have it link to category archive pages rather than actual pages, since most people won’t have a page called Prospects.

      On my install I run the default admin bar so I never noticed it.

      • Andrew says

        Thanks. Very simple and works great! I also noticed in loop.php the isset on line 21 got loose and escaped from the () so it just needs to be wrangled back in there to get the category display page back in order. Thanks so much for sharing all this!

  9. Josh says

    Had a really odd problem when I tried to install this on a brand new WP install (3.1 native install).

    Parse error: syntax error, unexpected T_STRING, expecting T_OLD_FUNCTION or T_FUNCTION or T_VAR or ‘}’ in /nfs/c07/h02/mnt/100054/domains/ on line 60

    The problem appears to be with this:

    class cmb_Meta_Box {
    protected $_meta_box;

    If I comment out the 2nd line (protected $_meta_box;), then the theme runs fine but none of the metaboxes show when trying to add a new contact.

    Wondering if I accidentially screwed something up??

    • Bill Erickson says

      I’m pretty sure the issue is that you’re running PHP4, and that bit of code you found depends on PHP5. WordPress is dropping support for PHP4 and switching to PHP5 with the next release (3.2), so this might be a good time to upgrade.

      • Josh says

        You hit it on the head. I was thinking “Surely, that’s not possible!” and then I checked my server settings and that domain was the ONLY one on PHP4. Thanks for the info. Fantastic contribution btw – thanks so much for sharing this. I’m EXACTLY in the same boat – I keep losing track of clients, potentials ,etc but the simplest system to use was Zoho and it was still a pain in the a$$ 🙂

  10. James says

    Was using version 1.2 and wanted to check out 1.3 replace 1.2 with 1.3 but none of the data entered using Version 1.2 is visible in 1.3 looks like the field names were modified and on a lessor note the .css file still shows the Version as 1.2.


    • Bill Erickson says

      Were the fields names changed or just the prefix? You can set the prefix in functions.php. I thought we left all the field names the same but I could be wrong (I can’t find a copy of 1.2 on my server).

      Here’s a few solutions:
      – Using phpMyAdmin or Sequel Pro, change the field names to those used in TwentyTen CRM 1.3. Something like : UPDATE wp_postmeta SET meta_key = replace(meta_key, 'client_phone', 'crm_client_phone');
      – Edit the theme files to use your old field names. If all that needs changing is removal of the crm_ prefix, just set $prefix = ''; right before the metaboxes are created in functions.php. If the fields need more changes, replace the actual field names in all the theme files.

      I don’t plan to release a new version of this any time soon, so don’t worry about changing the theme files. We’re considering rebuilding the whole theme to be independent of TwentyTen. When we do this, you’ll be able to customize the theme by creating a child theme of it (rather than TwentyTen CRM being a child theme of TwentyTen).

  11. Josh says

    I spent some time and I’m really digging this tool – thanks so much again Bill. One thing I might mention for a release for the future is that I ended up adding a “Clients” widget. I thought maybe you were bouncing between prospects and active projects so I wasn’t quite sure if I was interpreting how that workflow would happen.

    So instead I have “Prospects” which are just strictly leads. Once I convert them they turn into Active Projects, and then when I’m done they become Clients.

    May or may not be helpful for anyone but I thought I’d mention it.

    Thanks again for all your great work!

  12. Christine Green says

    How can I get the Prospects to show up either immediately or in 3 days rather than 10 days?

    • Bill Erickson says

      You’ll need to edit the widget (/twentyten-crm/lib/widgets/widget-old-prospects.php ).

      For the last 3 days, on line 34 change strtotime(‘-10 days’) to strtotime(‘-3 days’). For all prospects, just remove or comment out that whole line.

  13. Jim MacDonald says

    Thank-you bill for TwentyTen CRM. All is working fine but can’t seem to get search, archives and results showing up on 2 pages. Active Prospects and Prospects. How do I fix?

    Error if search is done. And same error message if clicked on Archives.

    Parse error: syntax error, unexpected T_ISSET, expecting ‘(‘ in /xxxx/xxxxx/public_html/prospects/wp-content/themes/twentyten-crm/loop.php on line 21

    Here is line 21 & 22 from loop.php

    The pages: To get the download link to show results a download page was created. However if a page is created for Active Prospects, Prospects, Results still no prospects show up on the pages.

    10 day & older Prospects and Active Prospects do show on on the “home data/stats page”, just not listing on their separate pages.

    Thank you.

    • Bill Erickson says

      isset is throwing an error? That’s really strange. Try deleting lines 21-25 (it’s basically a notification that the current post is in the trash).

      You’ll need to create custom page templates for those as well. I’ve built the page template for Downloads but not any others. You can use category archives for things like Prospects and Active Projects (/category/prospects) but if you want to do any custom query like prospects that are 10 days or older you’ll need to do a custom page template for that. Take a look at /lib/widgets/widget-old-prospects.php to see what the query for that page should look like. First you’ll do a query for all prospects, then you’ll skip ones that are not 10 days or older: if ($post->post_date > date(‘Y-m-d’, strtotime(‘-10 days’))) continue;

      • Jim MacDonald says

        Thanks for your speedy help bill. Search is working like a charm. Removed lines 21-25 as suggested plus 2 26 &27.

        Gotcha with the pages understanding. Thanks.

        • Jim MacDonald says

          Wow. Got it looking pretty using Meta Box’s and widgets after mucking around with it. Getting a simple, easy to mold into your own prospect processing system. Yet a powerful prospect flow by answering status, summary, reason and action. Cool.

          Then I blew it up – it’s when all is going fine but it’s been a long day and you get lax on making back ups of changes. And all I was doing was putting in text.

          After blowing it up, it had changed back into a regular wordpress dash board.

          Up loading a fresh copy functions.php from download brought it back. But when clicked on widgets it says it “Isn’t Widget Aware – No sidebars defined. Browsing to home page and there are three column text but no links. No links in drop down box either. (Functions.php has the links and stuff about set up, so I though a fresh up load would fix.)

          All my “Status Categories” and and (testing) contacts entered into twentyten-crm are there but are unable to show because widgets don’t show up to set up.

          I’ve ftp new fresh php pages from download functions, single page even loop and header and footer even styles. What file should I ftp to get widgets showing back up?.

          Thanks Bill – Can’t wait to get TwentyTen-CRM purring again.



          • Bill Erickson says

            Hmm that’s strange. The sidebars are defined in functions.php so I’d start there. Look at a blank copy of twentyten-crm and ensure you have the same code for sidebars. If that doesn’t work, I’d install a new copy of twentyten-crm and slowly copy/paste your changes from the original. When something breaks you’ll know that’s where the error is.

  14. Christopher Ross says

    Wonderful Bill, I’ve been using this off and on for a couple months now and can’t tell you what a pleasure it’s been.

  15. Alex says

    This is great! It’s a bit limited for what I need personally, but that you’ve done it is fantastic. Any thoughts on having a capability of tying in a contact form functionality in here so that when someone submits a request, it auto populates the data in the CRM?

    • Bill Erickson says

      I’m actually doing that right now with my contact form 🙂 When I get back from vacation I might write another post on how to do it, but here’s a quick summary:

      – Install “Gravity Forms” and “Gravity Forms + Custom Post Types” on your CRM site
      – Create a form with all the fields of your contact form you’d like filled out. You’ll want to make most of them post meta or taxonomies. You can also have hidden fields (I’m using that for Date of Inquiry)
      – Create a page called Form and add the contact form to it
      – Create a page template called template-form.php and remove all style from it (we’ll be embedding this page)
      – If you’re using Registered Users plugin to prevent others from logging in, use a filter to exclude the form page from the login restriction (or else your iframe will have a login box). See code below
      – Either drop an iFrame into your contact page or create a page template on your real site linking to your form page on the CRM site.

      // Exclude Form from login
      add_filter('registered-users-only_exclusions', 'crm_form_exclusion');
      function crm_form_exclusion($exclusion) {
      $exclusion[] = 'form';
      return $exclusion;

  16. Greg Turner says

    I am just now discovering this theme. Thank you very much. I am considering a couple of modifications that I’d like to have to make it more useful to me. I am not sure I have the time to implement, nor how difficult it would be, having not yet looked at the code.

    I’d like to have:
    1. Every prospect/client has available to them a page(s), password protected, that allows them to view info about their project, as well as allowing them to communicate to me instead of using email.
    2. Being able to have multiple projects per client.

    I welcome any comments on my desired modifications. Doable? Feasible? What do you all think?

    • Bill Erickson says

      It’s doable, but would require such heavy modification that your best bet would be to build it from scratch. I’d recommend building that on top of BuddyPress, since BP has private messaging, groups, and extended profiles built-in. Instead of having a custom post type called Contacts, you would create a new user and have all the client data associated with that profile. You could then create a custom post type called Projects, or repurpose something already in BP like Groups for it.

  17. Vijay Sharma says

    Excellent Theme Bill. I just started playing with this child theme and the experience is completely delightful. I will post more comments once I try more hands on this theme.

  18. kate says

    Is there anyway that this can be used by multiple users where contacts are ‘owned’ and only seen by the owner?

Leave A Reply