| Gadget Developer Guide | In their simplest form, gadgets for Blogger are "Google Gadgets". If you aren't familiar with Gadgets yet, take a look at the Developer Guide to get started. |
| Social Gadgets in Blogger | OpenSocial and Friend Connect APIs enable gadgets to tap into the blog's community to engage the blog's author and audience. |
| Accessing Blog Data from the Gadget | Blogger's JSON APIs give gadgets access to a blog's post and comment data, letting them leverage the context of the surrounding content. |
| Best UI Practices for Bloger Gadgets | Best practices for making your gadget look good across the large set of blog styles and layouts. |
| Example Gadget | A simple example gadget implementing best practices. |
| Testing your gadget in Blogger | How to test your gadget in Blogger. |
| Submit your gadget to Blogger | Now that your gadget is bug-free and beautiful, tell the world about it! |
Blogger's social features are based on the blog's community of Followers. Followers are the group of readers that publicly declare their interest in the blog and gain access to the blog's social network. A blog's Followers are displayed in the Followers Gadget on the blog, which is installed by default on all new blogs:
Blog authors also see how many Followers they have on their Blogger Dashboard:

And Followers, in turn, see summarized updates for the blogs they follow on their own Blogger Dashboard:

Followers form a loose knit, public community around a blog and its content.
Under the hood, Followers are powered by Google Friend Connect and OpenSocial. This means that every blog is a Google Friend Connect site, and every follower is a Google Friend Connect member.
This also means that followers can add Friend Connect friends in Blogger, letting them overlay their personal social network on top of the blog. For example, when you sign in to Friend Connect, the Followers gadget shows your friends who also follow that blog.
Blogger exposes all of this social data to developers via Google Friend Connect and OpenSocial APIs. Below is how OpenSocial terms map to Blogger concepts:
OWNER FRIENDS == Followers of a blogOWNER == the blogVIEWER FRIENDS ==
friends of the current viewer of the blog, if the viewer is logged into Friend Connect.OWNER ADMINS == blog administrators in Blogger.comStandard OpenSocial gadgets will work unmodified in Blogger, though we
highly recommend adding
support for skins to ensure the best end user experience. Any gadget that requires OpenSocial (via <Require
feature="opensocial-0.8" />) will gain access to both the standard
OpenSocial APIs and the extended Friend Connect APIs.
The Friend Connect
sample gadget is a useful reference when building Friend Connect gadgets for Blogger.
When added to a blog, the Friend Connect sample gadget displays exactly what various
OpenSocial APIs are returning at any time, making it a helpful tool when building and debuging
your gadget. Once you've created a test blog, add the sample gadget to your
blog by going to Blogger.com and clicking Layout -> Add a Gadget ->
Add Your Own. Then enter the sample gadget's URL: http://www.google.com/friendconnect/gadgets/sample.xml.
See Gadgets for Google Friend Connect for more details and examples of building Google Friend Connect gadgets. Note that Blogger automates all of the gadget snippet generation and rendering.
Blogger provides read-only blog data access to gadgets. The API retrieves public post and comment data for the blog hosting the gadget. Developers can opt to retrieve the data directly in Blogger's JSON format, or retrieve the URL of the underlying Atom feed for future use.
The API is available as the google.blog feature; a gadget that depends
on the data can require this feature. If you'd like your gadget to optionally access blog data
but still be compliant with other Google Friend Connect containers you can make the feature
optional.
getPostsJson(callback)
Retrieves feed of recent posts for the current blog, returning it as JSON to the callback.
getPostsFeedUrl()
Returns the URL of the Atom feed of all posts for the current blog.
getCommentsJson(callback)
Retrieves feed of recent comments (across all posts on the blog), returning it
as JSON to the callback
(format documented here).
getCommentsFeedUrl()
Returns the URL of the Atom feed of all recent comments.
When a gadget is being displayed on an individual post page, these methods
access the data for that post. If the gadget is not on an individual post page,
these return null. You can use getCurrentCommentsFeedUrl()!=null
as a test to indicate the gadget's environment.
getCurrentPostJson(callback)
Retrieves the current post as JSON, or null if there is none.
getCurrentCommentsFeedUrl()
Returns the URL of the Atom feed for recent comments on the current post, or null if there is no current post.
getCurrentCommentsJson(callback)
Returns the feed of recent comments for the current post, returning it as JSON
to the callback (format documented here).
This snippet calculates the word count for the various authors on a blog based on the last few posts, using each author's OpenSocial ID as a key for ease of lookup later.
...
// Calculate wordiness of blog authors:
function onLoadFeed(data) {
if (data.rc != 200) {
w(["Error loading blog data"]);
return;
}
var feed = data.data.feed;
var word_counts = new Array();
var wordiness = new Array();
for (var i = 0; i < feed.entry.length; i++) {
var entry = feed.entry[i];
var word_count = entry.content.$t.split(/\s/).length;
var osid = getOpenSocialId(entry.author[0]);
var author = entry.author[0].name.$t;
var authorid = getOpenSocialId(entry.author[0]);
var key = [author,authorid];
if (wordiness[key]==undefined)
wordiness[key] = word_count;
else
wordiness[key] += word_count;
}
var disp = new Array();
for (var k in wordiness) {
disp.push(k + " : " + wordiness[k] + " words");
}
w(disp);
}
// Return the OpenSocial ID for an author if available
function getOpenSocialId(person) {
var extendedProperty = person.gd$extendedProperty;
if (extendedProperty && extendedProperty.name == "OpenSocialUserId") {
return extendedProperty.value;
} else {
return null;
}
}
// Write output to a display element on the gadget
function w(arr) {
var str = "<ul>";
for (var e in arr) {
str += "<li>"+arr[e]+"</li>";
}
str += "</ul>";
document.getElementById('display').innerHTML = str;
}
Bloggers want to look good on the web. Follow these best practices so your gadget blends seamlessly with the many themes bloggers use.
In Blogger, the available width for your gadget depends both on the blog's template, and on the location where the gadget is inserted in the blog. The sidebars in Blogger.com templates range from 150px - 360px wide, though some templates have sidebars that resize to be wider when the browser window is stretched. In addition blog administrators can overwrite the default sidebar width.
In addition, gadgets can be added to the blog's side bar, header, or footer regions as shown by the orange rectangle in the images below.
This means your gadget should be flexible to work well at almost any width. Be sure to test your gadget in a variety of sizes in the blog before submitting your gadget.
By default, gadgets are 200 pixels high. You can use the <ModulePrefs> attribute height="nn" to specify a static height that is bigger or smaller than the default. However most gadgets will need to dynamically change their height. Follow
these guidelines to dynamically resize the height of your gadget.
Yikes, we have a bug!: Currently the skins feature only works if you also include
<Require feature="opensocial-0.7"/> or <Require feature="opensocial-0.8"/>.
We are fixing this bug and will update the Blogger
Developer Group as soon as the fix is released.
|
The skins feature provides access to key Blogger theme parameters. This feature is shared between Blogger and Google Friend Connect and the same skin parameters are used in both. In Blogger, the parameters are automatically inherited from the blog's template, so gadgets can easily blend in with the look and feel of the containing page. Blog owners can also override skin values if they wish to do so.
To access the parameters, a gadget asks for the skins feature:
<Optional feature="skins" />
It can then access parameters via the API, setting styles of elements via DOM manipulation:
<$("someElement").style.borderColor = gadgets.skins.getProperty('BORDER_COLOR');
These parameters are the most critical to use, and are always provided by the container. Each of these maps to an equivalent CSS style and can be added to HTML elements.
BORDER_COLOR
Color of border of gadget, or 'transparent'
if no border desired. Use this for the style of any border around the entire
gadget; do not assume that the border is always visible (many blogs do not
frame gadgets with borders).
CONTENT_BG_COLOR
Background color to use for main portion of gadget. This usually matches the
background color of the blog's sidebar, but in any case is chosen by the
container to make gadgets look good.
CONTENT_LINK_COLOR
Color of links in the main portion of gadget; chosen by the container to be
readable against CONTENT_BG_COLOR, work well with
CONTENT_TEXT_COLOR, and be consistent with links elsewhere on
the page.
CONTENT_TEXT_COLOR : Color of primary or most-displayed text in
main portion of gadget; chosen by the container to be readable against
CONTENT_BG_COLOR and consistent with text on the rest of the
page.
FONT_FACE
Font face to use by default; chosen to be consistent with the rest of the
content.
These may be used by a page owner to further tweak appearance on a per-gadget basis. They are not needed for all gadgets, but if your gadget uses these concepts, it should allow these variable to control their style.
CONTENT_HEADLINE_COLOR
Text color for titles or headlines as opposed to body text. Defaults to
CONTENT_TEXT_COLOR.
CONTENT_SECONDARY_TEXT_COLOR
An alternative color for secondary text that complements
CONTENT_TEXT_COLOR. Defaults to CONTENT_TEXT_COLOR.
CONTENT_SECONDARY_LINK_COLOR
Color for links in secondary text. Defaults to CONTENT_LINK_COLOR.
ENDCAP_BG_COLOR
Color for top and bottom cap sections for the gadget; defaults to
CONTENT_BG_COLOR.
ENDCAP_LINK_COLOR
Color for links within top / bottom cap sections; defaults to
CONTENT_LINK_COLOR.
ENDCAP_TEXT_COLOR
Color for text within top / bottom cap sections; defaults to
CONTENT_TEXT_COLOR.
ALTERNATE_BG_COLOR
Used for alternating rows in large list; defaults to
CONTENT_BG_COLOR
CONTENT_VISITED_LINK_COLOR
Visited link color; defaults to CONTENT_LINK_COLOR.
Each element, style, or graphic you add to your gadget, is something else that might clash with the containing blog's style. You want your gadget to blend seamlessly into as many blogs as possible. Avoid adding elements that cannot be skinned using the above defined skin parameters.
Do not add a title into your gadget's UI. Blogger will add the title automatically outside of the gadget in the same style as other gadget titles on the blog.
Most importantly, test your gadget on a number of different blogs. Modify the blog's background color, text color, and font face to ensure your gadget blends with a wide range of templates.
Here is a very simple Friend Connect powered gadget that takes advantage Blogger's JSON API. The gadget displays the current post's comments and highlights the comment if it was made by the viewer's friend. When the gadget is embedded in a blog, it will match the blog's style because it inherits several skin parameters.
The example gadget is also hosted here: example gadget, or you can download it.
<?xml version="1.0" encoding="UTF-8"?>
<Module>
<ModulePrefs height="300" title="BlogSocial">
<Require feature="opensocial-0.7"/>
<Require feature="google.blog"/>
<Require feature="skins"/>
<Require feature="views"/>
</ModulePrefs>
<Content type="html">
<![CDATA[
<script type="text/javascript">
var friendProfiles = {};
var blog;
function goToCanvas() {
var view = gadgets.views.getSupportedViews()['canvas'];
gadgets.views.requestNavigateTo(view);
}
/**
* This method is called after your friend data is loaded. It parses the friend data and
* saves the profile ids of your friends, then fetches the blog data.
*/
function onLoadFriends(data) {
if (data.responseItems_.viewerFriends.data_ == null) {
document.getElementById("output").style.textAlign = "center";
if (gadgets.views.getCurrentView().getName() == "canvas") {
document.getElementById("output").innerHTML = 'Sign in using the link above';
} else {
document.getElementById("output").innerHTML =
'<a style="color:' + linkColor + '" href="javascript:void(0);"
onclick="goToCanvas();">Sign in to Friend Connect!</a>';
}
return;
}
var friends = data.responseItems_.viewerFriends.data_.array_;
for (var i = 0; i < friends.length; i++) {
var id = friends[i].fields_.id;
friendProfiles[id] = "true";
}
// Get the feed data
blog = new google.Blog(function() {
// This callback is run as part of the constructor of google.Blog to signify
// that everything was initialized. Once the constructor has
// completed and then call getCommentsJson
blog.getCommentsJson(onLoadFeed);
}, window.name);
}
/**
* This method parses the feed data that was returned by the call to fetch the blog data.
*/
function onLoadFeed(data) {
var list = document.getElementById("output");
if (!data.data) {
list.innerHTML = "An error occured fetching the feed data";
}
data = data.data;
if (!data.feed.entry || data.feed.entry.length == 0) {
list.innerHTML = "No comments on this blog!";
}
for (var i = 0; i < data.feed.entry.length; i++) {
var entry = data.feed.entry[i];
var dt = document.createElement("DT");
dt.style.paddingTop = "10px";
var dd = document.createElement("div");
var href;
for (var j = 0; j < entry.link.length; ++j) {
if (entry.link[j].rel == "alternate") {
href = entry.link[j].href.replace(/#/, "#comment-");
}
}
var a = document.createElement("A");
a.style.color = linkColor;
a.setAttribute("href", href);
a.appendChild(document.createTextNode(entry.author[0].name.$t + " wrote..."));
dt.appendChild(a);
dd.appendChild(document.createTextNode(entry.content.$t));
list.appendChild(dt);
list.appendChild(dd);
// extendedProperty is Blogger's extension to ATOM 1.0 that contains the
// OpenSocial user id of the author if the author is a public follower
// of the blog. This field will not be present if the author is not a
// public follower of the blog.
var extendedProperty = entry.author[0].gd$extendedProperty;
if (extendedProperty && extendedProperty.name == "OpenSocialUserId") {
if (friendProfiles[extendedProperty.value]) {
dt.style.backgroundColor = "yellow";
dd.style.backgroundColor = "yellow";
}
}
}
}
var linkColor;
var textColor;
var backgroundColor;
function initData() {
textColor = gadgets.skins.getProperty('CONTENT_TEXT_COLOR');
document.getElementById("output").style.color = textColor;
linkColor = gadgets.skins.getProperty('CONTENT_LINK_COLOR');
document.getElementById("canvas-link").style.color = linkColor;
backgroundColor = gadgets.skins.getProperty('CONTENT_BG_COLOR');
document.body.style.backgroundColor = backgroundColor;
// Show canvas mode link if appropriate
if (gadgets.views.getCurrentView().getName() != "canvas") {
document.getElementById("canvas-link-container").style.display = "block";
}
var req = opensocial.newDataRequest();
req.add(req.newFetchPersonRequest('VIEWER'), 'viewer');
req.add(req.newFetchPeopleRequest('VIEWER_FRIENDS', {}), 'viewerFriends');
req.send(onLoadFriends);
}
gadgets.util.registerOnLoadHandler(initData);
</script>
<div style="display:none;float:right;font-size:80%" id="canvas-link-container">
<a id="canvas-link" href="javascript:void(0);" onclick="goToCanvas();">Canvas mode</a>
</div>
<div style="clear:both"></div>
<div id="output" style="overflow:auto; height:270px;font-size:90%"></div>
]]>
</Content>
</Module>
Since a gadget for Blogger is a Google Gadget, follow this guide for testing and preparing your Google Gadget for publication. One complete, read and follow the sections below describing how to test your gadget in Blogger.
Create a test blog with some post and comment data to use during testing:
If you've built an OpenSocial gadget you'll also want to add some followers to your site:
Now you're ready to start testing.
The functionality and appearance of your gadget depends on the blog that contains it. Therefore, the best way to debug your gadget is to test it in the context of an actual blog on Blogger.com. Above we described how to create a test blog, below we discuss how to add your gadget to your test blog and debug it on the blog.
First, make sure that your gadget XML file is hosted on a public web server, and that you have a test blog set up. From Blogger.com, go to Layout -> Add a Gadget -> Add your Own, enter your gadget's URL, and then save. The gadget will be added to your blog; click View Blog to view and test your gadget in the blog.
| Tip: If you've built a Friend Connect gadget, you can use the Google Friend Connect test gadget to help you debug your own gadget. Add the gadget (http://www.google.com/friendconnect/gadgets/sample.xml) to your test blog below your own gadget. The Google Friend Connect test gadget will display exactly what the APIs are returning at any time, so it makes a great comparison tool when developing and testing your gadget. |
As you test your gadget, you'll inevitably discover bugs and need to make corrections to your gadget XML file. You should disable gadget XML caching while you're tweaking the XML (otherwise, your changes won't show up on the blog). If you are testing an OpenSocial gadget, you can use the setNoCache method to disable caching. To do this, edit your blog's template and add the JS code:
<script src='http://www.google.com/friendconnect/script/friendconnect.js' type='text/javascript'></script> <script type="text/javascript">google.friendconnect.container.setNoCache(1);</script>
Note: The above code disables gadget caching when viewing your gadget on a blog. Unfortunately this does not disable caching when viewing your gadget in a blog's canvas mode or when "previewing" your gadget in the Blogger gadget directory. We are working on fixing this, but in the meantime you might try renaming your gadget to avoid caching in these circumstances.
Remember to remove this script before doing performance tests, and don't do this on a blog that has significant traffic since it will disable caching for all OpenSocial gadgets on the blog, making the blog load slowly.
Blogger provides a standard UI for adding and configuring gadgets. You should test that
any UserPrefs you've defined can correctly be configured by the blog administrator
in Blogger.com.
From Blogger.com, click the Layout tab, then click Add a Gadget. From the Gadget Diretory, choose Add your own. This allows you to add your gadget by its URL (note: the gadget must be hosted on a public web server).
When you add a gadget, it will display a preview and show any UserPref
parameters that can be configured. Test updating various configuration values and
adding your gadget to your test blog. Confirm your gadget works as expected on the
blog itself.
In Blogger, the available width for your gadget depends on the location it is inserted. Gadgets can be added to the blog's side bar, header, or footer regions as shown by the orange rectangle in the images below.
From Blogger.com, click the Layouts tab for your test blog. Drag your test gadget into the following regions, and click Save to view and test your gadget in those locations.
Also test the gadget in the sidebar of several different templates, since sidebar widths vary from template to template. From Blogger.com, click the Layout tab for your blog. Then click Pick a new Template. From the Template Picker, test that your gadget works well in the side bar of these templates:
As described above, your gadget should use skinning parameters to inherit the blog's style including text colors, background colors, and font face. Test that your gadget correctly inherits the blog's style by testing it on a variety of different blog templates.
From Blogger.com, click the Layout tab. Then click Pick a new Template. From the Template Picker, confirm your gadget correctly inherits styles from the following templates:
You may want to also edit the blog's Fonts and Colors directly. From the Layouts tab, click Fonts and Colors to control specific font and color choices for the blog and verify they are correctly inherited by your gadget.
Once you've throughougly tested your gadget, and followed Blogger's Best UI Practices, you're ready to submit your gadget.