WordPress and Blackbird Pie: “There was a problem connecting to Twitter”

I have been using WordPress longer than a lot of people. I think I first moved from Windows Live’s blogging platform to WordPress around 2007. Because I’ve been here a long time, I’ve got some plugins that have been around for a long time. One of those is the Twitter Blackbird Pie WordPress Plugin.

The Blackbird Pie plugin was great when it came out. It let you use an embed code to add a live tweet directly into a post. It looked something like this:

[blackbirdpie id=”507693704581500928″]

The id was the unique id for one individual tweet. Twitter was just getting popular and this seemed really cool.

Later, Blackbird Pie got smarter and you could just give it the URL for the tweet on Twitter’s site.

[blackbirdpie url=”http://twitter.com/sympmarc/status/507693704581500928″]

The WordPress crew noticed the Blackbird Pie plugin and they even added it to WordPress in 2010. Instead of using the [blackbirdpie] embed code, you could just drop the url directly into your post. But dang it, it still wasn’t working for me.

I assumed the problem was that Twitter kept changing their interface and APIs and Blackbird Pie stopped working, regardless how you used it. For probably a couple of years now, all my Blackbird Pie -enabled tweet links have been broken. Each one has been showing the message “There was a problem connecting to Twitter”.

I’ve tried quite a few times to fix this, but I’ve gotten nowhere. All of the forum posts out there say things like “It was such a great plugin. Why doesn’t it work anymore?” The owner of the plugin seemed to give up on it, too.

WordPress 4.0 “Benny” came out today and I immediately upgraded, as I am want to do. One of the things I noticed in the release notes was that Twitter embeds are supposed to just work natively. “Well, why haven’t they been working on my site?”, I asked myself.

I don’t know why it occurred to me to do it, but I decided to uninstall the Blackbird Pie plugin. Presto, change-o, all was right with the world. Well, with tweets embedded in my test post. The problem was the Blackbird Pie plugin itself!

You can fix this on your blog by searching for all of the Blackbird Pie embed codes and switching to plain old WordPress embeds.

  • Go to Plugins and Deactivate and/or Deletel the Blackbird Pie plugin
  • Search for all of your posts with the [blackbirdpie] embed code by going to http://YourWordPressBlog/wp-admin/edit.php?s=blackbird
  • For each of those posts, edit it and copy the url to the tweet
  • Delete the embed code line
  • Paste the tweet url into your post

That should do it!

SPTechCon Social Demo

[important]

Mark Miller (@EUSP) and I did a webinar on Friday, March 15, 2013 at  to show the demo again and take questions about how we built it. If you’d like to look at the demo yourself, check out the publicly available page on NothingButSharePoint.com. The video is embedded below.

[/important]

It’s not every day that I get to create something in SharePoint with a Magic button.

Magic Button

I few weeks ago, Mark Miller pinged me asking if I’d be interested in helping him with a demo for his keynote at SPTechCon. When Mark asks, I tend to ask “how high” simply because it’s usually something fun. Sometimes, it’s even useful.

The basic idea was to show a social dashboard in SharePoint without letting on that we were using SharePoint. As you might imagine, none of this went along as linearly as I’m going to describe it. We tried various different things, added and removed columns, and widgets, etc. What I’ll describe is the end result.

First, I knew I wanted to use jQuery, jQueryUI, and SPServices, so I took a copy of default.aspx in a basic Team Site and added the following references. (Yes, I prefer the old Web Part Page over the Wiki pages. It’s much easier to work with. The Wiki pages tend to vomit markup all over what I do.)

<link href="Scripts/social_home_page.css" rel="stylesheet" type="text/css" />
<!-- Reference the jQueryUI theme's stylesheet on the Google CDN. Here we're using the "Start" theme -->
<link href="/ajax/libs/jqueryui/1.10.0/themes/start/jquery-ui.css" rel="stylesheet" type="text/css" />
<!-- Reference jQuery on the Google CDN -->
<script type="text/javascript" src="/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<!-- Reference jQueryUI on the Google CDN -- >
<script type="text/javascript" src="/ajax/libs/jqueryui/1.10.0/jquery-ui.min.js"></script>
<!-- Reference SPServices on cdnjs (Cloudflare) -->
<script type="text/javascript" src="/ajax/libs/jquery.SPServices/0.7.2/jquery.SPServices-0.7.2.min.js"></script>
<!--<script type="text/javascript" src="http://cdn.dev.skype.com/uri/skype-uri.js"></script>-->
<script type="text/javascript" src="Scripts/social_home_page.js"></script>

Next, I altered the markup for the page in SharePoint Designer. This was a demo, so there was zero concern about repeatability, of course. It’s nice to have that sort of freedom once in a while. By default, the page has a table with two columns set to 70% (left) and 30% (right) width. I simply changed that markup to have four columns, each with 25% width. In each of the two new table columns, I added a Web Part Zone. I wanted to drop as much of the social stuff as I could into the page using Content Editor Web Parts so that I could explain it more easily, like in this blog post. In edit mode, the page looked something like this: 3-11-2013 09-52-09 Next I added some CSS to the social_home_page.css file:

#s4-ribbonrow {
  display:none;
}
.s4-titlerowhidetitle {
  display:none;
}
#s4-leftpanel {
  display:none;
}
#MSO_ContentTable {
  margin-left:0;
}
#MSO_ContentTable table td {
  padding:3px;
}

This simple CSS removed all of the chrome we normally see on the page. In other words, we’ve removed the SharePoint from SharePoint to a large degree. The ribbon, title area, and Quick Launch are all totally hidden. (No screen shot for this – you wouldn’t see anything!) At this point, I had a page that looked like a big white nothing in the browser. Time to add the fun stuff. In Twitter, you can create widgets that display tweets from Twitter much like you can create different streams in HootSuite or TweetDeck. You can find this capability in Settings: 3-11-2013 09-58-00 I created three different widgets:

  • search stream for “EUSP”
  • search stream for “SPTechCon”, and
  • search stream for “SharePoint”

There are a few settings which give you basic control over the look and feel. If we were implementing this “for real”, it would probably make sense to make calls against the Twitter API and get the raw data so that we would have full control over the markup and visuals.3-11-2013 10-05-29 When you create the widget, you get a little snippet of markup and script which you can embed in a Web page. Those snippets are very simple. Here’s what the snippet for EUSP looks like:

<a class="twitter-timeline" href="https://twitter.com/search?q=EUSP" data-widget-id="306449761781817344"></a>
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>

I put each snippet into a TXT file so that I could reference them in CEWPs. For the EUSP stream, I have a TXT file called twitter_search_eusp.txt in a Document library, and I just point to that file in the CEWP’s Content Link. This gets the three Twitter streams into the page:

3-11-2013 10-25-53

We also wanted to show something from Yammer, since it plays so importantly into Microsoft’s social story. While there are Yammer Web Parts available, I decided to go the widget route here as well. If you look under Apps in the Yammer Web interface, you’ll find Yammer Embed, which eventually takes you to the Yammer Embed page. There, you’ll find a PDF document that explains how to embed a Yammer feed. (Note to the Yammer folks: This isn’t a very clear process. Opportunity for improvement.)

Here’s what I ended up with for the SPYam feed. Note that I created my own id for the container so that it would fit into my page logic easily.

<script data-app-id="hyB2pTvrL36Y50py8EWj6A" src="https://assets.yammer.com/platform/yam.js"></script>
<script>
yam.connect.embedFeed({
  container: '#yammer-spyam-embedded-feed',
  network: 'spyam' // update with your own
});
</script>
<div id="yammer-spyam-embedded-feed"></div>

For some reason, the Yammer authentication mechanism simply won’t work in my page in Internet Explorer 9, so I switched to Firefox at this point, where I had no problems. (Another place for improvement, Yammer folks. However, it may well be that my IE9 is just sick.)

3-11-2013 10-43-14

Now we have all four streams we want in the page, at least in Firefox, for me.

I had seen some Twitter traffic about Dan McPherson’s lastest entries in the SharePoint Games under the Leap moniker. There are two offerings right now: LeapBackup and LeapMessages. Mark and I thought it would be cool if we could use LeapMessages to send a text message with the contents of a Tweet. I can imagine several use cases for this. Perhaps you work at Burger King, your Twitter account is hacked, and you need to notify the execs…

LeapMessages is really simple to implement. You just sign up on the Leap site, give the site URL and your Office365 credentials (it only works on Office365 right now), and Leap creates a list in your site called LeapMessages. If you add an item to that list, the LeapMessages engine grabs it (it polls every 30 seconds) and sends it out as a text from their gateway. Easy-peasy.

To implement this, I pulled a demo cheat. Since it takes a little time to load up the three Twitter streams and the Yammer stream, I set it up so that when I hovered over the Magic button (see below for more info on the button), this script would run, adding an SMS link at the bottom of each tweet in the three streams. I just had to wait until the three Twitter streams were loaded before I did the hover trick.

$("div.showSharePoint").hover(function () {

  if (!loadedSMS) {

    loadedSMS = true;

    $("iframe[id^='twitter-widget-']").contents().find("ul.tweet-actions").prepend("<ul><li><a class="SMS-send">SMS</a></li></ul>");
    $("iframe[id^='twitter-widget-']").contents().find(".SMS-send").click(function (e) {

      e.preventDefault();
      var thisTweet = $(this).closest("div.footer").closest("li");
      var thisTweetText = thisTweet.find("div.e-entry-content").text().trim();
      var thisTweetFullName = thisTweet.find("div.header span.full-name").text().trim();
      var thisTweetNickName = thisTweet.find("div.header span.p-nickname").text().trim();
      messageText.val("Interesting tweet from " + thisTweetFullName + " (" + thisTweetNickName + ") " + thisTweetText);
      countChars();

      $("#dialog").dialog("open");

    });
  }

}, function () {
  // Nothing to do
});

I added this markup at the bottom of the page for the dialog that would pop up when I clicked the SMS links.

<div id="dialog" title="Send SMS Message">
  <p class="validateTips">All fields are required.</p>
  <head>
    <meta name="WebPartPageExpansion" content="full" />
  </head>
  <form>
    <fieldset>
    <label for="phoneNumber">Phone Number</label>+1
    <input type="text" name="phoneNumber" id="phoneNumber"
    class="text ui-widget-content ui-corner-all" />
    <br />
    <label for="messageText">Message</label>
    <textarea rows="5" cols="40" name="messageText"
    id="messageText" value=""
    class="text ui-widget-content ui-corner-all"></textarea>
    <div id="charCount"></div></fieldset>
  </form>
</div>

When I clicked the SMS link, this script drove the dialog and wrote the entered data into the LeapMessages list using SPServices.

dialogDiv.dialog({
  autoOpen : false,
  height : 300,
  width : 500,
  modal : true,
  buttons : {
    "Send Message" : function () {
      var bValid = true;
      allFields.removeClass("ui-state-error");
      bValid = bValid && checkLength(phoneNumber, "Phone number", 10);
      bValid = bValid && checkRegexp(phoneNumber, /^([0-9])+$/i, "Phone number can only contain digits.");
      // From jquery.validate.js (by joern), contributed by Scott Gonzalez: http://projects.scottsplayground.com/email_address_validation/
      if (bValid) {
        // Send the SMS message
        $().SPServices({
          operation : "UpdateListItems",
          async : false,
          batchCmd : "New",
          listName : "LeapMessages",
          valuepairs : [
            ["ReceiverMobileNumber", "+1" + phoneNumber.val()],
            ["Message", encodeXml(messageText.val())]
          ],
          completefunc : function (xData, Status) {}
        });
        $(this).dialog("close");
      }
    },
    Cancel : function () {
      $(this).dialog("close");
    }
  },
  close : function () {
    allFields.val("").removeClass("ui-state-error");
  }
});

There are a few helper functions referenced above, and here they are:

var loadedSMS = false;

var dialogDiv = $("#dialog");
var phoneNumber = $("#phoneNumber"),
messageText = $("#messageText"),
allFields = $([]).add(phoneNumber).add(messageText),
tips = $(".validateTips");

function checkLength(o, n, num) {
  if (o.val().length > num || o.val().length < num) {
    o.addClass("ui-state-error");
    updateTips(n + " must be  " + num + " digits.");
    return false;
  } else {
    return true;
  }
}

function checkRegexp(o, regexp, n) {
  if (!(regexp.test(o.val()))) {
    o.addClass("ui-state-error");
    updateTips(n);
    return false;
  } else {
    return true;
  }
}

function updateTips(t) {
  tips.text(t).addClass("ui-state-highlight");
  setTimeout(function () {
    tips.removeClass("ui-state-highlight", 1500);
  }, 500);
}

function countChars() {
  var messageLen = messageText.val().length;
  var errorClass = messageLen > 160 ? "class='ui-state-error'" : "";
  $("#charCount").html("You have used <span " + errorClass + " >" + messageLen + "</span> of 160 characters");
}
messageText.keyup(function () {
  countChars();
});

I decided to add one last piece of functionality. I couldn’t figure out how frequent the Twitter polling was, but when there was a new tweet in any any of the streams, I wanted to highlight it. To do this, I added this bit of script. It ran every three seconds to see if anything new had shown up, and if it had, it highlighted the counter at the top of each Twitter stream.

// Show tweet counters
setInterval("countTweets()", 3000);

function countTweets() {
  $("iframe[id^='twitter-widget-']").each(function () {
    var tweetCount = $(this).contents().find("li.tweet").length;
    var thisCounter = $(this).prev(".tweet-counter");
    if (thisCounter.length === 1) {
      var currCount = thisCounter.html();
      if (tweetCount != currCount) {
        thisCounter.addClass("ui-state-highlight");
        setTimeout(function () {
          thisCounter.removeClass("ui-state-highlight", 1500);
        }, 10000);
      }

      thisCounter.html(tweetCount);
    } else {
      $(this).before("<div class="tweet-counter">" + tweetCount + "</div>");
    }
  });
}

The Magic button is just a div. Yes, I violated best practices by making it a div instead of a real button. Don’t try this at home.

<div class="showSharePoint">Magic</div>

The Magic button contains the reveal. When I clicked on it, this script ran, unveiling the fact that the page was, in fact, a SharePoint page. There were very few oohs or aaahs that I could hear, which was a little disappointing, but hey, maybe I pushed it too fast or something.

// Set up the Magic button
$("div.showSharePoint").click(function () {

  var thisValue = $(this).text();

  if (thisValue == "Magic") {
    $("#RibbonContainer").hide();
    $("#s4-ribbonrow").slideDown(5000);
    $("#RibbonContainer").slideDown(5000, function () {
      $(this).fadeIn(1000)
    });
    $(".s4-titlerowhidetitle").fadeIn(5000);
    $("#s4-leftpanel").fadeIn(5000);
    $("#MSO_ContentTable").animate({
      "margin-left" : "150px"
    }, 5000, function () {
      // animation complete
    });
    $(this).text("No Magic");
  } else {
    $("#RibbonContainer").slideUp(5000, function () {
      $(this).fadeOut(1000)
    });
    $("#s4-ribbonrow").slideUp(5000);
    $(".s4-titlerowhidetitle").slideUp(5000);
    $("#s4-leftpanel").hide();
    $("#MSO_ContentTable").animate({
      "margin-left" : "0px"
    }, 5000, function () {
      // animation complete
    });
    $(this).text("Magic");

  }

});

So there you have it. I’m sure I’ve left some bits and bobs out of this in trying to make it consumable here, but I think I’ve gotten most of the important parts. All in good fun, and hopefully it got the message across that SharePoint doesn’t have to look like SharePoint and that we can do useful social stuff in SharePoint in many cool ways.

I’ve thought of a few neat things we could do with this, like storing the snippets in a SharePoint list and letting the user select which ones they want to see in their version of the page, dragging and dropping the streams into the order they like, and saving their settings for when they return. The possibilities with this stuff are really endless, depending on what you want to accomplish.

Have fun!

3-11-2013 11-47-29

What’s the Difference Between an "IT Pro" and a "Dev"?

Someone at Microsoft asked me whether I was an “IT Pro” or a “Dev” the other day in an official capacity, and I got a bee under my bonnet to figure out what the two terms actually meant. For a couple of years I haven’t really understood the terms, and since I figured I was the only one in the dark, I just kept my mouth shut about it. After all, I don’t *usually* like to look like I don’t know what’s going on. [Insert your joke about me knowing what’s going on here.]

http://twitter.com/#!/sympmarc/status/80835198262050817

I had always thought that the terms were Microsoft-driven, as I had never heard them (that I could remember) prior to becoming as Microsoft-focused as I have been the last few years with all of my SharePoint work.

I was surprised at the answers I got. They fell into several camps, which I would synthesize down to:

  • The terms are bogus and they annoy me
  • There is too much overlap to be meaningful
  • Please let me know when you figure it out

Here’s a smattering from the stream that my question generated. Note that there are some links to useful reading embedded in some of the tweets. If I missed something *you* said, and you’d like me to add it, please let me know.

http://twitter.com/#!/idubbs/status/80837768615436289

http://twitter.com/#!/idubbs/status/80842008255668225

http://twitter.com/#!/TeamEUSP/status/80849207069646848

The post to which Natasha referred is SharePoint: What in the world is an ITPro? on NothingButSharePoint.com‘s IT Pro channel.

http://twitter.com/#!/shaunocallaghan/status/80959717656104960

http://twitter.com/#!/stuartblank/status/80960802642866176

http://twitter.com/#!/shaunocallaghan/status/80961031635079168

http://twitter.com/#!/patman2520/status/80967843721654272

http://twitter.com/#!/SharePhantom/status/80968329828896768

http://twitter.com/#!/SharePhantom/status/80968603658227712

http://twitter.com/#!/katscasa/status/80968859158450176

http://twitter.com/#!/katscasa/status/80969918706745345

Sure, it’s totally unfair to ask people to define two confusing terms on Twitter, much less one clear one. But it still was interesting to me how little real consensus there was.

I think that the most cogent answer I got in 140 characters on Twitter was from Diane Golshan at Microsoft, who runs the @msuspartner account:

http://twitter.com/#!/msuspartner/status/81033532784381952

I didn’t particularly like that answer, either, because it included “build” twice. When I pointed that out, Diane responded that they “build” different things. Fair enough.

http://twitter.com/#!/msuspartner/status/81389597078196224

So what conclusions did I draw from all of this? Well, primarily that these artificial distinctions don’t really make sense to many people, that there’s not a clear common understanding of the terms, and that I definitely am not either. Or I’m both.

In any case, I’m pretty sure this isn’t the last time I’ll discuss this.

Collecting Souls: Knowing Your Social Media Strategy – Part Three

When I first started using the nascent Internet back in 1992 (How many of you were even alive – or at least out of Legos – by then? Raise ’em up!), there was little I could do to interact with it. Most content was static and commenting barely existed. There were very few “publishers”, and they were sharply skewed toward academics and others with access to University computer networks.

imageThere were, however, some content islands. I was a member of Prodigy and later CompuServe, and each had some places where one could express one’s self. As I remember, other than the early forms of chat rooms, there were discussions about stocks and some other investments, at least.

These content islands absolutely couldn’t support any crossover. Anything I posted in one was never going to be seen in another, and all of us thought that anonymity or identity walling was the way it would just be forever. (Sure, smarter people than I and pundits knew it would change, perhaps, but I’m a member of the unclean masses.)

Forward to the late 1990s, and there was an explosion of content islands as part of the Internet bubble. I worked for a company at the time called ArsDigita, and one of the things we did was help companies build their content islands, either by using our open source ArsDigita Community System (ACS) toolkit (a descendant of which is still available as OpenACS) or by hiring us to build them for them. One of the main goals for Internet sites was to make them “sticky”, meaning to increase the time someone would spend on them. A great lever to pull to make that happen was to create a community aspect for the site, and that’s exactly what ACS and those of us on the consulting staff tried to achieve. Make it interactive, and the eyeballs would stick around.

imageHowever many of these content islands there were during those days, they were still islands. It was like the manmade island structures off the shore of Dubai as opposed to the remoteness of the South Seas, perhaps, but they remained islands all the same.

Fast forward to the late oughts, and we started building bridges from island to island. Some outfits like Gravatar and the OpenID Foundation even built transportation hubs to move us easily from island to island. It started to feel like the teleporter from Star Trek; we barely felt the effects of the travel and we were able to interact with new cultures almost instantaneously. No longer was our persona isolated to a single island, where I might choose to have one “handle” on one island and another handle elsewhere. We’ve all gotten very used to linking up our island personas into one super-ego of self.

So what? Well, what this all amounts to is that it is no longer reasonable to assume that we can have unique, separate personas from Internet island to Internet island. For better or worse, we have all become citizens of the Internet world, passport in hand. There are many implications of all this, and some have profound implications for our current and future selves.

First, as opposed to the early days, content may as well be forever. Sure, islands occasionally submerge or become part of larger islands, but in general, the content we create – our Internet footprints on the beach – are going to be there for a good long time. What we may post as an angry comment on someone’s blog or as a cute photo with our virtual pants down isn’t going away anytime soon.

25 - Footprints on Beach, Northern California, United States
This travel blog photo’s source is TravelPod page: Eureka, Arcata and the Humboldt Coast

Second, we can’t realistically expect that we can manage separate personas as we often do in the meat world. I may act one way with my family, another with my mates in the pub, and another with my work colleagues, but on the Internet that is possible less and less. Someone in any of those groups is likely to follow me on Twitter, link with me on LinkedIn, read my blog, *and* friend me on Facebook. Suddenly my separate personas must meld together, or at least they will in the minds of the consumer.

The ginormous caveat in all of this is that a few assaholic moves on one island are going to follow you around the Internet world. In my [scarily almost 50 years] of experience, it works much like it does in consumerism. People remember your mistakes over your triumphs (unless they are *really* big triumphs) and carry the “lowest common denominator” opinion of you around with them.

imageThis may all sound sort of interesting, at least if you’ve managed to read this far. In practical terms, the way it has changed my thinking over the last year or two as I have tried to build some sort of personal brand for myself in the archipelago is that I must be my best self as much as possible.

I’ve chosen to use the Social Web professionally. As a solo practitioner, it sure beats advertising. That means that my every social move gets tacked onto my professional persona. When I tweet about my love for bacon, does it cloud a Muslim’s view of my capabilities as a SharePointilist? Does complaining about Microsoft’s sometimes abysmal documentation put me at risk in the technical community in which I’ve decided to be a member? Does tagging myself in a friend’s silly photo from college in 1981 put my possibilities for the next great consulting gig in jeopardy?

Lest you think I’ve become obsessively self-centered and sit in a darkened room contemplating my every move, rest assured that is not the case! I simply try to be cognizant from time to time that my every action may have an equal or *larger* reaction on the Social Web.

So what can you take away from this post? Well, just as every woman who has thought it would be funny to bare their chest for Girls Gone Wild and then wondered later “What the %#?$& was I thinking?”, pause once in a while and think about the persona you want to present to the world. If something is nagging at the back of your mind that maybe that little post isn’t such a great idea, hold off clicking on the Send button and read it over again, maybe a little later.

Think from time to time what your Social Media strategy is. Is it connected to your professional persona? Is it just for your silly side? Would you kiss your momma with that mouth? The Social Web is an amazingly rich and rewarding experience. Be sure to try the poi at the luau!

SharePointy Observations from Vacation

Yeah, I’m hanging out on a beach in Mexico (Morgan Freeman isn’t here; someone told me he stopped by many years ago), but I never really stop SharePointing; I’m a SharePointilist.

A few observations from the lounge chair, each of which will probably turn into a full post itself:

  • If you are publishing ANYTHING about SharePoint and there isn’t a very handy Tweet This button available, you’re missing out on exposure.
  • The #SPHelp hashtag is getting overused, misused, and is in danger of being burned just like the #SharePoint hashtag. Think very hard before using it.
  • If you are using SharePoint 2010 for your Internet-facing site, you ABSOLUTELY HAVE TO consider mobile users. If I kept a list of the sites on which I can’t access content from my iPhone lying in the sun this week, you’d be amazed. I’m talking big name sites that should know better.

Many thanks to Mike Greene (@webdes03) for babysitting SPServices for me while I laze. He’s oftentimes far better in his responses than I am, so please say thanks if he helps you.