Skip to content

Instantly share code, notes, and snippets.

@dtex
Last active May 30, 2019 20:42
Show Gist options
  • Save dtex/5c718a108f8a409ba3cbd105064c889f to your computer and use it in GitHub Desktop.
Save dtex/5c718a108f8a409ba3cbd105064c889f to your computer and use it in GitHub Desktop.
On Buckets and Chunks

On Buckets & Chunks

Buckets in the Past

Before responsive websites, buckets were used to divide a page into sections. A typical design might have a Header bucket, an Inline bucket, a Sidebar bucket, and a Footer bucket. Each bucket could have any number of chunks and those chunks could be resequenced within the bucket or moved to another bucket.

The chunks in a bucket were output with a call to the built-in bucket-handler template and could be one of three types. A text/html chunk, an client or server script (any one of several media types), or a server-side include.

There is a separate template for each of the three chunk types in the xsl-library/presentation folder.

If you needed custom HTML around each chunk you could leverage the bucket-handler's $before, $after, and $wrapper params. These were ugly and pretty limited and they assumed that every chunk in the bucket would have the same HTML before and after. Without these params chunks just had their body barfed into the bucket 🤮.

Son's Trick

As responsive websites came into vogue, web design evolved to meet the new technical and organizational requirements that came with them. Instead of having multiple buckets on a page, responsive designs tended to have a single, dominant, inline bucket with multiple, full-width chunks stacked on top of each other. These stacked chunks required that the design around each chunk vary to help visually seperate discreet pieces of content. Some people at BE have called this "Layer Cake" design.

The first approach to do this in SAM was to create many buckets on a page, each with its own XSL/HTML surrounding the call to bucket-handler. This approach was limiting as the layers could not be resequenced so the design of each page became inflexible. Also, there was a ton of buckets which was confusing.

Son realized that he could repurpose buckets so that a different template would be applied depending on the value of the content-group (AKA bucket). What used to be the inline bucket became a generic main content area with lots of chunks. The chunks would all be output in sequence order and a different template would be applied depending on the value of content-group (AKA bucket).

The Problem This Caused

Son's solution is smart and solves a real problem, but buckets are meant to be containers for a set of chunks. Using "bucket" to describe a type of chunk is unintuitive and makes it harder to understand what each bucket really is (a container or a type). More importantly, in scenarios where we really do need buckets to decribe content sets, we are forced to create complicated XPATHs for our main content area that excludes all the "real" buckets.

Collections reveal an additional new problem with Son's approach. Since collections are simply user defined buckets, we do not know in advance the names of all the buckets we would need to exclude from the "main" content call. While it may be possible to write an XPATH that looks at all the collections and excludes their member chunks, this is complicated enough that neither Son or I could figure it out in an afternoon. This does not bode well for people using SAM in the future.

My Proposal

Leverage Media Type parameters to specify a chunk "type". Note that "Chunk Type" is distinct from "Media Type". Media Type parameters are documented on this IANA Web Page. So instead of:

<chunk id="170" revision="5329" level="5" sequence="10">
  <title>Kim K.W. Rucker</title>
  <mime-type>text/html</mime-type>
  <meta name="Content-Group">
    <value>Three Columns</value>
  </meta>
  ...
</chunk>

We would have:

<chunk id="170" revision="5329" level="5" sequence="10">
  <title>Kim K.W. Rucker</title>
  <mime-type>text/html;type=Three Columns</mime-type>
  <meta name="Content-Group">
    <value>inline</value>
  </meta>
  ...
</chunk>

This way we preserve the meaning of Content-Group but still have the ability to apply a custom template by matching on the full Media Type like so:

<xsl:template match="/SAM/page/chunk[mime-type='text/html;type=Three Columns']">
  <xsl:param name="chunks" />
  <xsl:param name="wrapper" />

  <section class="columns columns--three">
    <div class="container">
      <div class="grid">
        <!-- Here we'd apply the text/html template -->
      </div>
    </div>
  </section>
</xsl:template>

Similarly, collections would use a collection param on the Media Type like so:

<chunk id="170" revision="5329" level="5" sequence="10">
  <title>FAQs</title>
  <mime-type>text/html;collection=accordion</mime-type>
  <meta name="Content-Group">
    <value>inline</value>
  </meta>
  ...
</chunk>
<chunk id="171" revision="5330" level="5" sequence="11">
  <title>First Question</title>
  <mime-type>text/html</mime-type>
  <meta name="Content-Group">
    <value>FAQs</value>
  </meta>
  ...
</chunk>

and our template would look like:

<xsl:template match="/SAM/page/chunk[mime-type='text/html;collection=Accordion']">
  <section class="accordion">
    <div class="container">
      <xsl:call-template name="bucket-handler">
        <xsl:with-param name="bucket-label" select="title" />
        // Here you could use $wrapper, $before and $after
      </xsl:call-template>
    </div>
  </section>
</xsl:template>

How Hard Will This Be?

THe changes in SAM are not that bad. I already have the collection Media Type parameter working and the code was minimal. The biggest drawback to this change will be that any site that uses Son's trick will need to be updated. Each chunk that uses a bucket to define a type will need to have it's bucket and mime-type updated and then we will need to update the templates accordingly. We won't be able to upgrade the site's SAM version until we do that.

Option 1: Update Existing Chunks

Depending on the complexity of the templates, this may be impractical as it would be a lot of work to port to the new style. Consider Adding collections and types to an existing "buckets as types" template

1. Update the Media Type

UPDATE    Chunk
SET       ChunkType = 'text/html;type=Three Columns'
FROM      ChunkMeta INNER JOIN
              Chunk ON ChunkMeta.ChunkFK = Chunk.ChunkPK
WHERE     (ChunkMeta.FieldValue = 'Three Columns')

2. Update the bucket

UPDATE    ChunkMeta
SET       FieldValue = 'Inline'
WHERE     (FieldValue = 'Three Columns')

3. Remove the "Type Bucket" from the list of available buckets

<xsl:variable name="CONTENT-GROUPS">Marquee,Inline,Featured (Left),Featured (Right),Carousel,Tabs,Accordion,Two Columns,Three Columns,Dynamic Columns,Aside</xsl:variable>

Becomes

<xsl:variable name="CONTENT-GROUPS">Marquee,Inline,Featured (Left),Featured (Right),Carousel,Tabs,Accordion,Two Columns,Dynamic Columns,Aside</xsl:variable>
<!-- "Three Columns" was removed

4. Update the templates Okay, so this is where all the work is and every template is different.

5. Repeat steps 1-4 for each of the "Type" Buckets

Or be awesome and write a SQL script that take a list of Type Bucket names as an array and updates all the SQL data at once

Option 2: Adding Collections to an Existing "Buckets as Types" Template

1. Add the Collection to the site variables This belongs in the root of your template and will cause the collection type to appear in the "Type" dropdown on the "Add a Chunk" dialog.

<xsl:variable name="TEMPLATE-VARIABLES">
	{
	  collections:["Accordion"]
	}
</xsl:variable>

2. Add a Collection Add a chunk, and choose your collection type from the "Type" dropdown. Make note of the "Chunk Name" as you will need it later.

3. Add a Template for the Collection At the minimum you must call collection-handler. Put in any HTML you want to wrap the collection.

<xsl:template match="chunk[mime-type = 'text/html;collection=Accordion']">
  <section class="accordion">
    <div class="container">
	<xsl:call-template name="collection-handler">
	    <xsl:with-param name="bucket-label" select="title"/>
	</xsl:call-template>
    </div>
  </section>
</xsl:template>

4. Exclude the Collection from the Main Chunk Output Somewhere in your template you are calling all the buckets for your main content area. You need to make sure the new Colelction (Chunk Name from step 2) is excluded. Here's an example from MPC where "Committees Accordion" is the name of the chunk we created:

<xsl:variable name="buckets" select="chunk[
        ($only = '' or contains($only, ./&bucket;))
        and ($except = '' or not(contains($except, ./&bucket;)))
        and not(./&bucket; = 'Footer')
        and not(./&bucket; = 'Committees Accordion')
        and not(
          ./&bucket; = preceding-sibling::chunk[1]/&bucket;
        )
]" />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment