Web Development

My First Redbooth API Demo

Shortly after joining Redbooth as an employee, I began playing with the collaboration platform’s application user interface. As a writer who also writes code, I was curious to see whether I could come up with something useful.

The Redbooth API makes use of the OAuth2 authentication method, which provides a standard way for a user of one application to give permission for another application to access protected resources. For example, once the test is past, an external application that has received the user’s blessing can retrieve access files stored in a Redbooth workspace or add tasks to a task list. The application retrieves a cryptographic authentication token from Redbooth, which it then uses as proof of its right to access these resources.

One of the first ideas I had was to display some sort of interactive user directory. I can imagine a few different scenarios where it might be handy to store some supplemental information about employee performance or vacation schedules in your own app, using the data structure you define rather than one provided within Redbooth.

This version shown below (which you can access live here) pulls the names and profile photos for all the other users in your organization and allows you to add notes to each of these mini-profiles.

Note that you’re welcome to use this application for real, as long as you’re willing to do so at your own risk; it’s not running on Redbooth’s secure infrastructure, and the data you add goes into a MySQL database on my server. If you have a serious application for something like this, you could use the code shown below as a starting point (if you’re working in PHP) or as inspiration for an app you might implement in the language of your choice, on your own server.

API demo
Once a redbooth user authorizes account access, this app displays a basic user directory with the option of adding notes to each user record.

The preliminary setup starts in initialize.php, which sends a request to to start the OAuth authentication process:



$apikey = 'KEY_GOES_HERE';
// make sure to url encode the redirect URL
$q = urlencode(''); //provide the url for auth.php on your server
// construct the authorization query with our apikey and the redirect URL
$endpoint = '' . $apikey . '&redirect_uri=' . $q . '&response_type=code';
//redirect to authorization URL
header("Location: " . $endpoint);


The main workhorse functions are in auth.php. In the previous step, we queried for a code to be used to kick off the authentication process. The code is returned as a GET query parameter appended to the redirect uri specified in initialize.php. The API key and API secret are used to verify that the user has given permission for access to his or her account. The remainder of the code in this script is devoted to sorting the user records by last name, formatting them for display, and setting up a JQuery/AJAX routine to post notes about each user to a local database.

Any existing notes are retrieved as part of a database routine that runs right before we start iterating through the user records retrieved from



<!doctype html>
<meta charset="utf-8">
<title>User Directory Demo</title>
textarea {
width: 600px;
border: thin solid blue;
height: 2em;
body {
background-color: #CC0000;
#content {
width: 700px;
padding-left: 15px;
padding-right: 15px;
margin-left: auto;
margin-right: auto;
background-color: #eee;

<div id="content">
<h1>Dave's unofficial API demo</h1>
<p>Once authorized, the app pulls a list of the other users in your organization from Redbooth. You can add a note to any user record by typing it into the blank and pressing enter.</p>

function rb_authorize () {

$code = $_GET["code"];
$apikey = 'KEY_GOES_HERE';
$appsecret = 'SECRET_GOES_HERE';

// make sure to url encode the return URL
$q = urlencode('');  //ex:

// construct the authorization query with our apikey and the returned code to get the access_token
$endpoint = '' . $apikey . '&client_secret=' . $appsecret . '&code=' . $code . '&grant_type=authorization_code&redirect_uri=' . $q;
// setup curl to make a call to the endpoint
$session = curl_init($endpoint);

// indicates that we want the response back
curl_setopt($session, CURLOPT_RETURNTRANSFER, true);
// post
curl_setopt($session, CURLOPT_POST, true);
// exec curl and get the data back
$data = curl_exec($session);

// remember to close the curl session once we are finished retrieveing the data
// decode the json data to make it easier to parse the php
$auth_result = json_decode($data);
// check for empty data
if ($auth_result === NULL) die('Error parsing json for auth result');

// Get the access_token
$_SESSION["access_token"] = $access_token = $auth_result->access_token;
return $access_token;

function get_me($access_token) {
// construct the query with the access_token to get the user's account details
$endpoint = '' . $access_token;

// setup curl to make a call to the endpoint
$session = curl_init($endpoint);
// indicates that we want the response back
curl_setopt($session, CURLOPT_RETURNTRANSFER, true);
// exec curl and get the data back
$data = curl_exec($session);
// remember to close the curl session once we are finished retrieveing the data
// decode the json data to make it easier to parse the php
$me = json_decode($data);
return $me;

if($_SESSION["access_token"] && !$_GET["new"])
	$access_token = $_SESSION["access_token"]; // todo - check expiration
// Get the returned code
$access_token = rb_authorize ();

$me = get_me($access_token);

// check for empty data
if ($me === NULL)
// try again to get current user data
$access_token = rb_authorize ();
$me = get_me($access_token);

if ($me === NULL) die('Error parsing json for /me');

// construct the query with the access_token to get the user's account details
$endpoint = '' . $access_token;
// setup curl to make a call to the endpoint
$session = curl_init($endpoint);
// indicates that we want the response back
curl_setopt($session, CURLOPT_RETURNTRANSFER, true);
// exec curl and get the data back
$data = curl_exec($session);

// remember to close the curl session once we are finished retrieveing the data

// decode the json data to make it easier to parse the php
$users = json_decode($data);
// check for empty data
if ($users === NULL) die('Error parsing json for users listing: '.$data);

$count = sizeof($users);

echo "<p><em>Fetched $count users</em></p>";

// get any status notes about the users from the database and put them in an array
// keyed to the redbooth username
include "db.php";
$sql = "SELECT * FROM status ORDER BY timestamp DESC";
foreach ($conn->query($sql) as $row) {
	$stat[$row['username']] .= '<p>'.$row['text'] . "<br /><em>posted by @" . $row["by"] .' at ' . date('F j, Y',strtotime($row["timestamp"]))."</em><p>\n";

foreach($users as $user)
	$uindex = strtolower(preg_replace('/[^A-Za-z]/','',$user->last_name.$user->first_name.$user->email));
$user_directory[$uindex] = sprintf("
<div style=\"float: right; clear:both\"><img src=\"%s\"></div>
<strong>First Name</strong>: %s<br />
<strong>Last Name</strong>: %s<br />
<strong>Email</strong>: %s
<textarea class=\"status\" id=\"get_%s\" subject_username=\"%s\" me_username=\"%s\"></textarea>
<div id=\"postresult_%s\" ></div>
",$user->avatar_url, $user->first_name, $user->last_name, $user->email, $user->username, $user->username, $me->username, $user->username, $stat[$user->username]);

foreach ($user_directory as $profile) 
	echo $profile;
<script src=""></script>
$( ".status" )
  .keypress(function() {
     if(event.keyCode == 13)
	PostRbStatus(this.getAttribute("subject_username"), this.getAttribute("me_username"), this.value)

function PostRbStatus(subject_username, me_username, message) {
$.post( "/rb/poststatus.php", {subject_username: subject_username, me_username: me_username, message: message})
	.done(function( data ) {
  $( "#postresult_" +  subject_username).html( data )
	.error(function( ) {


	$('#get_' + subject_username).blur();
	$('#get_' + subject_username).value('');

$( "textarea" )
  .on( "mouseenter", function() {
    $( this ).css({
      "border": "medium solid #CC0000",
	  "height": "5em"
  .on( "mouseleave", function() {
    var styles = {
      "border": "thin solid blue",
	  "height": "2em"
    $( this ).css( styles );

The db.php file is a standard database initialization using the PDO class.

$servername = "localhost";
$username = "USERNAME_GOES_HERE";
$password = "PASSWORD_GOES_HERE";

try {
    $conn = new PDO("mysql:host=$servername;dbname=tabmgr_rb", $username, $password);
    // set the PDO error mode to exception
    //echo "Connected successfully"; 
catch(PDOException $e)
    echo "Database connection failed: " . $e->getMessage();

The database access a simple table with this structure.

  `username` varchar(255) NOT NULL,
  `by` varchar(255) NOT NULL,
  `text` text NOT NULL,
  PRIMARY KEY (`id`)

Here is the server-side script that processes the data submitted for notes on each user. The output is captured by the client-side JavaScript and placed in a div above the previous entries in the database.

include "db.php";
		$username = $_POST["subject_username"];
		$by = $_POST["me_username"];
		$message = $_POST["message"];
		$sql = sprintf("INSERT INTO status (`username`, `by`, `text`) VALUES('%s', '%s', '%s') ", $username, $by, $message);
		$count = $conn->exec($sql);
			printf('<p>%s <br /><em>added by %s %s</em></p>',$message,$by,date('F j, Y'));
			echo "<p>Error adding note</p>";

Leica Cameras, Leitz and Zeiss Lenses, etc.

I’m currently seeking offers or advice on how to value several vintage cameras, mostly Leicas, as well as lenses and accessories. This collection also includes movie and portrait cameras. Most are from the 1950s and 1960s and some may go back to the 1940s. Full set includes an assortment of lens filters and adapters not shown here. These were handed down from my father and grandfather.

My grandfather was a veteran of World War I, so it’s possible some of these such as the Verascope stereo camera are older than I realize.

If interested, contact


5cm 1:2 Serial #1587970
5cm 1:2 Serial #1587970


5cm 1:2 Serial #1318695
(purchased 1956)

3.5cm 135 Serial#1290163
3.5cm 135 Serial#1290163 (from 1955)
LEITZ ELMARIT 90mm f/2.8 from 1962 Serial #1760690
LEITZ ELMARIT 90mm f/2.8 from 1962 Serial #1760690
135mm 1:4 Serial #1825635
Leitz Elmar 135mm 1:4 Serial #1825635


This may have collectors value. Serial #196867 10.5 cm 1:63

I believe this is an Alpine Elmar from the 1930s

serial # matches models manufactured in 1934, according to this reference

Leitz 5cm  1:2 Serial #380257 from 1937
Leitz 5cm 1:2 Serial #380257 from 1937


Leitz 3.5cm 1:3.5 Serial #1519731
Leitz 3.5cm 1:3.5 Serial #1519731 (wide angle lens, mfg 1957, purchased 1961)


Leitz 50mm? 1:4.5 Focotar (don't see serial #)
Leitz 50mm? 1:4.5 Focotar (don’t see serial #)
M3 #1
M3 #1 – based on serial #, this was manufactured in 1959

M3 dates based on this list

M3 #2 with case
M3 #2 – based on serial #, this is from 1955
M3 #3
M3 #3 – based on serial #, from a batch manufactured 10/11/61
Leica IIf, paperwork says 1955

Leica IIf according to this serial # lookup

Verascope movie camera
Verascope stereo camera

See or

Bolex 8mm movie camera
Bolex 8mm movie camera – model B8, 1953





















Web Development

Collaboration Technology: The Evolution of Business (Video)

Following the publication of my Social Collaboration for Dummies book, I participated in several public speaking events like this focusing on the business use of social technologies.

Web Development

Video Interview from MediFuture 2014 (Representing InformationWeek Healthcare)

In my role as the editor overseeing InformationWeek Healthcare, I was the one being interviewed for a change at the MediFuture Conference in Tampa, where I moderated a panel on user engagement and the importance of the new wearable health monitoring tools.

Web Development

WordPress for Toastmasters Project

One of my recent web development projects is a customization of WordPress for use by Toastmasters clubs, available as software as a service at

This is an extension of RSVPMaker, my most successful and widely used WordPress plugin. I added Toastmasters-specific features while serving as Vice President of Education (and later President) at Club Awesome Toastmasters. Now I’m taking what I developed for my own selfish purposes and making it more widely available.

The Toastmasters extensions may or may not see the light of day as a published plugin, but I’m offering a free version of the hosted software to those who want a subdomain such as – with the possibility of upgrades for those who want to host at their own domain.

You can see a bit of how it works in the video below.

Web Development

Video: Collaboration Panel, Discussing “Social Collaboration for Dummies”

This is a panel discussion I participated in as part of my Social Collaboration for Dummies book tour.

Web Development

Social Collaboration for Dummies book launch at JiveWorld

JiveWorld Moderation
Doing onstage interviews at JiveWorld; here with Lisa Araonson of Allstate

The release of my Social Collaboration For Dummies book turned out to be just in time for JiveWorld13, the Jive Software user conference I participated in. I do mean just in time — the books turned up in the warehouse at Wiley the Friday before the event and had to be overnighted to Los Vegas to catch up with me.

In addition to a holding a book signing at the show, I participated on an analysts panel and conducted a series of onstage interviews with JiveWorld customers Allstate, American Airlines, and Steelcase.

One of the neat things about the Allstate story is they tried instituting social collaboration a few years ago but very tentatively, deciding at that time that employees associated with crucial operations such as claims shouldn’t have access to the enterprise social network because it might be a distraction to them. Today, the organization has done a 180 — figuring out that the claims group needs this technology precisely because it is so critical. In part, that’s because social collaboration could fill a knowledge transfer role, giving younger workers a medium for getting questions answered by more experienced workers, with the record of those Q&A interactions preserved online. With the addition of a mobile client, the social network has also become more useful to personnel in the field, who often need to look up a document or get a question answered while on the go.

Allstate and Steelcase both had a combination of stories about internal social networking and the creation of collaboration groups for external constituencies (independent insurance agents and furniture dealers, respectively).

American Airlines was using the social collaboration network partly to demonstrate a new spirit of transparency and cooperation to a workforce badgered by years of turmoil. At the same time, it is moving cautiously in how it opens up that resource because of workforce and union tensions. Another common large company use for social collaboration is to bridge the gaps between business units brought together through mergers and acquisitions, and American has some plans to use the network to help it integrate United Airlines — assuming that one survives a current challenge by the justice department.

Web Development

Recovering from a Database Crash (Hack?)

This site is running on a backup copy of the database that is missing many recent blog posts and comments. I’m working on getting it back in shape.

Facebook Tab manager Web Development WordPress

Facebook Tab Manager 2.8.7 Adds Theme / Template Options, Preloader Image

I figured out how to address a few requests for greater customization options and also how to add a preloader image if a pages are sometimes slow to load. The theme option was also partly inspired by my recent work on a Facebook extension to WP e-Commerce, which was a sort of spin-off of Facebook Tab Manager code.

I’m just starting the process of moving most documentation over to, so see the links below for more details.

Facebook Tab manager Web Development WordPress WP FB Commerce

Facebook Extension for WP e-Commerce

Based on the success of Facebook Tab Manager, I got contacted a few weeks ago by the makers of the WP e-Commerce plugin to consult on creating an extension that would allow merchants to display products with a version of their storefront embedded in a Facebook business page tab.

An early version is available for download here – – and I’m at the stage where it would be helpful to get feedback. Also, since I don’t currently run a live e-commerce store, I’d like to to see what this looks like with a real assortment of products loaded into it. I’ve got a little Facebook Specials demo store running on the Carr Communications Facebook page, but the product listings aren’t particularly realistic.

This isn’t up in the WordPress plugins repository yet. Here is the description from the readme.txt

WP FB Commerce

WP FB Commerce is a companion plugin to GetShopped’s famous WP e-Commerce. Market featured products or your whole catalog on Facebook.

Contributors: davidfcarr, mufasa
Donate link:
Tags: facebook, iframe, page tab, e-commerce, wp-e-commerce, shop, cart, paypal, authorize, stock control, ecommerce, shipping, tax
Requires at least: 3.0
Tested up to: 3.2.1
Stable tag: 0.1


WP FB Commerce is a companion plugin to GetShopped’s famous WP e-Commerce. Display featured products or your whole catalog on Facebook and allow customers to check out directly within your Facebook business page.

This early release includes code adapted from Facebook Tab Manager for WordPress, customized for the e-commerce application. Use the provided theme for displaying products on Facebook or provide your own.

WP FB Commerce was created for GetShopped by Carr Communications Inc.

For more information about WP e-Commerce visit


  1. Upload the folder wp-fb-commerce to the /wp-content/plugins/ directory
  2. Activate the plugin through the ‘Plugins’ menu in WordPress
  3. Optionally, copy the fb-ec-theme subfolder to /wp-content/themes/ directory. This will allow you to modify the template files and style.css independently of the plugin code. It may also perform better.
  4. Register the URL for your storefront in the Facebook Developers utility (see explanation under Frequently Asked Questions).

Frequently Asked Questions

How do I add my storefront to Facebook?

WP FB Commerce displays your storefront as a tab on a Facebook business page. You will register a URL pointing to your web server in the Facebook Developers utility at

Click ‘Create a New App’ and follow the instructions. Many of the fields on the app registration form are optional. The most critical fields to fill in for our purposes are in the Page Tab section where you will enter a Page Tab Name, Page Tab URL, and Secure Page Tab URL. You must be able to host SSL secured / https pages for this to work properly.

You can find the URLs to record on the ‘Products -> FB Featured’ and ‘Settings -> WP FB Commerce’ pages. You have a choice of either displaying products from the default view of your WP e-Commerce product catalog or a select list of featured products set on the Products -> FB Featured screen. The URLs include a query string parameter in the form of ?fbx=1 for the featured products list or ?fb=commerce for the default listing.

After saving the settings for your “app”, click the link on the left hand sidebar to View App Profile Page.

From the profile page, click the link for ‘Add to My Page’. Facebook will display a listing of all the pages you own or have editing rights to. Click the Add to Page button next to the page or pages you want this storefront view to appear on. Then navigate to your business page, and you should see the new tab displayed on the menu on the left side of the page.

If you are logged in as an administrator of the page, an ‘Edit’ link will be displayed at the bottom of the list of tabs (navigation links within the content for your page). This allows you to delete or rearrange the tabs. If you have a long list of tabs, you may need to click ‘More’ before the ‘Edit’ link will be displayed.

You can edit or rearrange the tabs.

How do I select Facebook featured products?

Look for an additional menu item under Products titled FB Featured. You may select up to 20 products to be displayed as featured offers.

How do I customize WP FB Commerce?

  • Visit the settings screen at Settings -> WP FB Commerce. You can add header (for example, including a logo) or footer, add custom CSS to be added dynamically, and specify navigation options.
  • You can create your own themes specifically for use with WP FB Commerce. When you add a theme to the ‘wp-content/themes’ and select it from the Settings -> WP FB Commerce, it will be displayed instead of your default theme when your site is viewed from within Facebook.

How does WordPress know to display the Facebook theme?

When a visitor first accesses the Facebook Page Tab containing your storefront, the query string at the end of the URL tells WordPress to display the Facebook theme. As the visitor continues to navigate through the product catalog, a PHP session variable tells WordPress to continue to display content with the Facebook theme.

Note: If the visitor subsequently navigates to your external website, this session variable can cause the website to be displayed within this alternate theme. However, this should only be momentary — a JavaScript routine detects that the site is no longer being viewed within the Facebook iframe and redirects with a parameter that terminates the session, causing your site to be viewed within its normal theme.

What is the to-do list for this plugin?

  • Improve display of shopping cart contents after user clicks the Add to Cart button. Would be good to have something similar to the sliding cart effect used in the WP e-Commerce sidebar widget. However, the Facebook layout doesn’t leave room for a sidebar.
  • Better AJAX / JavaScript effects for product display and checkout. Need a better way of showing that items have been added to cart. JavaScript for ‘fancy_notifications’ doesn’t seem to be working properly.
  • A way of giving special discounts to users who come through the Facebook channel.
  • The ability to add an additional discount, or display special offers, for people who have “Liked” the merchant’s Facebook page. (Currently, this status is detected and stored in the session variable $_SESSION[“like”] but the variable is not being used to affect product display or pricing.)
  • A hacked version of the thickbox JavaScript is provided — altered to address certain positioning issues when the lightbox is displayed within an iFrame. Would appreciate help from anyone who can come up with a better solution.


  1. A product listing embedded in a Facebook business page.



This is a preliminary test release. Shopping and checkout functions should function much the same as they would on an independent website. However, the plugin needs further testing with WP e-Commerce options.