Widget Developer Documentation

Collections & Content Sets

We’re about to get into deep water. Be sure you’re confident with all of the basics of widget development before tackling this subject.

Collections are about looping, or repetitive data handling. A collection is a widget setting type that allows your users to enter multiple values in a repeating widget. You’ve probably encountered collections before. They’re used in some of the core widgets (e.g., the Responsive Menu, and most of the carousel widgets).

In fact, just to refresh your memory, here’s how the Responsive Menu widget looks when a user is setting it up on a page:

The “Add” button at the bottom allows the user to enter as many menu items as they like. While this is the typical way people will enter items in this particular widget, it’s the least interesting (and least common!) way to work with collections in general.

Content sets

Note
This document does not cover the creation of content sets. You can learn more about the basics of how Moboom lets you build content sets in the main documentation site.

Content sets are designed to work well with collections. Together, they make the creation of structured content extremely easy. And as we will see, the implementation frees the widget developer from needing to know whether the content is being generated manually (as in the example above) or if it is being pulled from a content set. 

A simple menu

In order to see the way these features work together, we’re going to build a simple menu widget. As with the Responsive Menu, it will use a collection that allows the user to enter as many menu items as needed.

First, create a new widget in the widget builder, called Simple Menu.

Enter the settings that correspond to the screenshot above. Try it yourself before reading the next paragraph.

The settings for this widget are just a single collection, called Menu Items (using the setting name menuItems). Inside the collection are two settings, which are both text. (Don’t use the link data type for this widget. We need to use the text data type, for reasons that we will discuss shortly.) Be sure you use the field names link and text.

The PHP code for the Simple Menu looks like this:

echo "<ul>";
$menuItems = Moboom::getWidgetSetting('menuItems');
foreach( $menuItems as $oneMenuItem) {
    echo "<li><a href='" . $oneMenuItem['link'] ."'>" . $oneMenuItem['text'] . "</a></li>";
}
echo "</ul>";

That doesn’t look like a lot of code, but it’s worth going through it slowly.

On line 2, we retrieve the widget setting for the collection. With a collection type, this API call returns an array, rather than a single entry.

On line 3, we initiate a loop through the array. And on line 4, we retrieve the two attributes of each menu item (link and text), which are keyed to the setting names that you created earlier.

Review that short PHP snippet before moving on. It’s simple, but it has everything we need for working with collections and content sets.

At this point, you should have a simple but working menu widget. Try using it on a page, and enter menu items the way you normally would.

Create a content set

The purpose of this next part of the exercise is to link the new menu widget to a content set. That way, the user won’t type the menu items directly into the widget settings. Instead, the menu will be managed through a content set.

This menu widget isn’t the most likely real-world example of why you’d want to link to a content set. However, it’s the simplest. If you master the next few steps, you’ll be building blog archives, news aggregators, and product listings in no time.

Go ahead and create a managed content set, using the properties shown here. Be sure you select the text type for both of the attributes.

Add a few items to your content set.

Our sample content set:

Changing your widget code to accommodate content sets

The widget already works with content sets.

That’s right: the code above that outputs menu items does not care where the data comes from. Whether the menu items are manually-entered or drawn from a content set, the widget code is identical. Boom.

Using content in your widget settings

You’ve probably already used content sets in other widgets. This feature is documented on the Moboom documentation site. At right is a screenshot from the widget editor after it’s been linked to the content set. 

Notice that there is only one entry in the collection in the widget editor. This single entry will be unpacked and converted into an array by the widget renderer. Be careful here: when using a content set as the data source, you must use exactly one entry in the widget editor’s collection. If you use more than one, the widget renderer will only send your code one entry from the content set, which is probably not what you want. Try it out to see how it breaks.

Just to repeat that: when the widget renderer sees a collection with a single entry made up of content-aware links, it will send you an array of items from the content set, rather than just a single item.

Here you can see why we selected the text data type for links, rather than the link data type. With text, we can easily use the content-aware selector to connect to the content set. The content set contains a URL, but it uses a text field to do the connecting.

We’re done working with the menu for now. Next, we’ll look at how to work with larger content sets.

Context, paging, and working with larger content sets

By default, the widget renderer will send your widget code ten entries at a time. (If there are fewer than ten entries in the content set, you will get all of them.) If your widget works with larger content sets, you’ll need to build a solution that handles multiple pages of data. Here’s how.

The API has a method that will tell you everything you need to know about the data your widget has received. Here is the code necessary to retrieve what Moboom calls the context of a data query. The context describes the data source from which the array in Moboom::getWidgetSetting() is generated:

// retrieve the context from the widget renderer
//
$context = Moboom::getContext();
$startAt  = $context['from'];
$pageSize = $context['size'];
$total    = $context['total'];

These variables are read-only. Inside the widget code, you cannot request different or additional data. You can, however, build links that the user can click on to retrieve different data, because the context can be set using query variables on the URL. For example, here’s how to build a link that requests page 2 of a large data set:

$url = Moboom::getPageSlug() . "?page=2";
echo "<a href='$url'>Page 2</a>";

Here is a complete list of query variables you can use in the URL to ask the widget renderer to retrieve specific data from a content set.

  • page — Retrieves a specific page of data.
  • size — Set the page size, so you can retrieve more or less data at a time.
  • id — Retrieves a single item from a content set.
  • sort — Sets the query to run using ascending or descending sort.
  • sortby — Indicates which parameter to sort on
  • q — Creates a query which selects a single record. For example, ?q=CustomerId:1500 will select the record with CustomerId = 1500.

And here is some sample code you can use to get you started building a paging interface. The code below is just an extension of the previous example that sets the page number; it does not change the page size from its default of ten. You are welcome to experiment with that in your own code.

// retrieve the context from the widget renderer
//
$context = Moboom::getContext();
$startAt  = $context['from'];
$pageSize = $context['size'];
$total    = $context['total'];

// convert the context into usable numbers
//
$numPages = ceil( $total / $pageSize);
$curPage  = 1 + floor( $from / $pageSize);

// this function builds the correct query string
// that will set the context for a specific page of data
//
function buildWidgetQuery( $page, $pageSize ) {
    return http_build_query( array(
        'page' => $page,
        'size' => $pageSize
    ));
}

// build links to next/prev pages
// (building a full list of page links
//  is left as an exercise for the reader)
//
$slug = Moboom::getPageSlug();

// make a PREV button
//
if ( $curPage != 1) {
    $queryString = buildWidgetQuery( $curPage - 1, $pageSize);
    echo "<a href='$slug?$queryString'>Previous</a>";
}
// and a NEXT button
//
if ( $curPage < $numPages) {
    $queryString = buildWidgetQuery( $curPage + 1, $pageSize);
    echo "<a href='$slug?$queryString'>Next</a>";
}

Re-sorting

Once you have a set of data in your widget code, you can re-sort it if necessary. Note that the following code does not do a new data query; it simply sorts the data you’ve already been given. However, this can be useful in smaller data sets.

The example below sorts a collection based on one of the fields called time.

// re-sorting collections. the collection array is keyed,
// so we need to use uasort
//
function cmp( $a, $b) {
    return strcmp( $a['time'], $b['time']);
}
$milestones = Moboom::getWidgetSetting( 'milestones');
uasort ( $milestones, cmp);