Code Modules — Docs

Markup Modules

Markup Modules

Screenshot of Blog Home 1 from the Sample Website.

Screenshot of the “Blog Home 1” Index Page on the Sample Website.

Introduction

Unlike the other high level modules which are singletons — Pages, Tech, Nav, and Elements — most websites will have many Markup modules. Markup modules have a generalized flow: entry ⟶ templates/ ⟶ lists/ ⟶ items/ ⟶ types/.

The example that follows illustrates the differences and uses of each of these parts.

Blog Posts Module Example

Problem

On the Sample Website, there are some blog posts. These need to provide information for a variety of different pages in different formats. There's a full blog post that appears on its own page. There are two blog post home pages that display a portion of the post and an image in different formats. And there's a text list of “Recent Blog Posts” with dates and titles. Individual recent blog posts need to also show up in the navigation under the Blog dropdown item. One should be able to rethink the markup for any of these items without having to consider the individual blog posts themselves.

Desired Results for Blog Posts

Full Blog Post Markup

In the full post (with text elided), the markup needs to be in this form:

Desired Markup for Blog Post
1<div id="blogPostContent" class="col-lg-8">
2<!-- Preview Image -->
3 <img class="img-fluid rounded" src="images/editorial/Sausage_Assortment_on_a_Grill-40-1430x760.jpg" alt="Sausage Assortment on a Grill, photo by Hasmik Ghazaryan Olson via Unsplash.">
4 <hr>
5<!-- Date/Time -->
6 <p>
7 Posted on Wednesday, August 11, 2021
8 </p>
9 <hr>
10<!-- Post Content -->
11 <h4 class="mb-4">
12 Are Hot Dogs Sausages?
13 </h4>
14 <p class="lead">
15 Instinctively, you know that they are. But there’s an unmistakable difference between a sausage sandwich and a hot dog. So what gives?
16 </p>
17 <p>Bacon ipsum dolor amet brisket salami ... Short ribs pancetta beef pork.</p>
18 <hr>
19</div>
20<!-- /#blogPostContent /.col-lg-8 -->

List of Blog Posts - “Blog Home 1”

An individual blog item appears as one of a <ul> list with a link to the full post.

Desired Markup for Home Page 1
1<div class="col-md-12 col-lg-12 mb-5">
2 <div class="card h-100">
3 <a href="blog-sausages.html" target="_blank"><img class="card-img-top" src="images/editorial/Sausage_Assortment_on_a_Grill-40-1430x760.jpg" alt="Sausage Assortment on a Grill, photo by Hasmik Ghazaryan Olson via Unsplash."></a>
4 <div class="card-body">
5 <h4 class="card-header">
6 Are Hot Dogs Sausages?
7 </h4>
8 <p class="card-text">
9 Instinctively, you know that they are. But there’s an unmistakable difference between a sausage sandwich and a hot dog. So what gives?
10 </p>
11 <a href="blog-sausages.html" class="btn btn-primary" target="_blank">
12 Read More →
13 </a>
14 </div>
15<!-- /.card-body -->
16 <div class="card-footer text-muted">
17 Posted Wednesday, August 11, 2021
18 </div>
19<!-- /.card-footer -->
20 </div>
21<!-- /.card -->
22</div>
23<!-- /.col-md-12 /.col-lg-12 -->

List of Blog Posts - “Blog Home 2”

For Blog Home 2, each blog post is marked up with divs as a different style of card than Blog Home 1.

Desired Markup for Home Page 2
1<div class="card mb-5">
2 <div class="card-body">
3 <div class="row">
4 <div class="col-lg-6">
5 <a href="blog-sausages.html" target="_blank"><img class="img-fluid rounded" src="images/editorial/Sausage_Assortment_on_a_Grill-40-1430x760.jpg" alt="Sausage Assortment on a Grill, photo by Hasmik Ghazaryan Olson via Unsplash."></a>
6 </div>
7 <div class="col-lg-6">
8 <h2 class="card-title">
9 Are Hot Dogs Sausages?
10 </h2>
11 <p class="card-text">
12 Instinctively, you know that they are. But there’s an unmistakable difference between a sausage sandwich and a hot dog. So what gives?
13 </p>
14 <a href="blog-sausages.html" class="btn btn-primary" target="_blank">
15 Read More →
16 </a>
17 </div>
18<!-- /.col-lg-6 -->
19 </div>
20<!-- /.row -->
21 </div>
22<!-- /.card-body -->
23 <div class="card-footer text-muted">
24 Posted Wednesday, August 11, 2021
25 </div>
26<!-- /.card-footer -->
27</div>
28<!-- /.card -->

Recent Blog Posts Sidebar

For the recent blog post sidebar item, each blog post appears, without an image, as one of a <ul> list with a link to the full post.

Desired Markup for Recent Blog Posts
1<li class="mb-3">
2 <a href="blog-sausages.html">
3 <small>
4 Wednesday, August 11, 2021
5 </small>
6 <br />
7 Are Hot Dogs Sausages?
8 </a>
9</li>

Markup Modules Generally

Markup modules are designed to return a unit of markup for inclusion in the visible part of an HTML page. Markup modules are found in /app/modules/markup/ and are one of five high level module folders: markup/, pages/, tech/, nav/, and elements/. See the High Level Modules page for more on the different types of modules.

Module File List

Here’s a list of the files found in the Blog module. When creating a new module, one can duplicate and rename the blank/ module, change the #MODULE# value in the entry entry.shtml root file, and then start customizing the module. The entry file at the root of the module — the only file ever called from outside the module — is highlighted. It’s a violation of CM conventions to ever call a file inside a module other than the entry file. If you find yourself wanting to do that, stop yourself and figure out how to get the same information you want through a call to the entry file.

app/modules/markup/blog/
blog/
├── _notes.txt
├── entry.shtml
├── items/
│ ├── blank.shtml
│ ├── buns.shtml
│ ├── sausages.shtml
│ └── toppings.shtml
├── lists/
│ ├── default.shtml
│ └── recent.shtml
├── templates/
│ ├── nav.shtml
│ ├── parts/
│ │ ├── bottom.shtml
│ │ └── top.shtml
│ ├── post.shtml
│ ├── recent.shtml
│ ├── teasers-with-images-on-side.shtml
│ ├── teasers-with-images.shtml
│ └── teasers.shtml
└── types/
├── list.shtml
├── nav.shtml
├── single.shtml
├── teasers-with-images-on-side.shtml
├── teasers-with-images.shtml
└── teasers.shtml

The folder names are an important part of the convention, but most of the filenames (other than “entry.shtml”) can be whatever you wish. While the structure can get more complicated with the addition of subfolders, all Code Modules Markup modules look similar to this in structure.

app/modules/markup/blog/ Just Folders Shown
blog/
├── items/
├── lists/
├── templates/
│ ├── parts/
└── types/

Calling the Module

The output of the Blog module is needed in the individual Blog Post pages, Blog Home 1, Blog Home 2, and the Recent Blog Posts sidebar widget.

The #TEMPLATE# variable is defined in the calling file. In this example, for the individual blog post, there’s an #ITEM# variable defined as well.

From the individual Blog Post pages, an individual blog post can be called like this:

Call to Blog Module from app/modules/pages/templates/blog-sausages.shtml
<!-- #bbinclude "/markup/blog/entry.shtml"
#bbincludeoptions#="inline=true"
#TEMPLATE# = 'post'
#ITEM# = 'sausages'
-->
<!-- end bbinclude -->

Calling a list of all blog posts for Blog Home 1 is done like this:

Call to Blog Module from app/modules/pages/templates/blog-home-1.shtml
<!-- #bbinclude "/markup/blog/entry.shtml"
#bbincludeoptions#="inline=true"
#TEMPLATE# = 'teasers-with-images'
-->
<!-- end bbinclude -->

The call from Blog Home 2 is identical except for the value of the #TEMPLATE# variable:

Call to Blog Module from app/modules/pages/templates/blog-home-2.shtml
<!-- #bbinclude "/markup/blog/entry.shtml"
#bbincludeoptions#="inline=true"
#TEMPLATE# = 'teasers-with-images-on-side'
-->
<!-- end bbinclude -->

The call for the sidebar widget of recent blog posts is similar:

Call to Blog Module for Recent Blog Posts Sidebar Widget
<!-- #bbinclude "/markup/blog/entry.shtml"
#bbincludeoptions#="inline=true"
#TEMPLATE# = 'recent'
-->
<!-- end bbinclude -->

Entry File and Module Flow

Markup modules usually follow a particular order — a flow — through the module. A call to the module always starts at the entry.shtml entry file. It is directed through the parts of the module as follows:

entry ⟶ templates/ ⟶ lists/ ⟶ items/ ⟶ types/.

Here is an abbreviated view of the Blog module with the flow order specified.

app/modules/markup/blog/ Just Entry and Folders Shown
blog/
├── entry.shtml ①
├── items/ ④
├── lists/ ③
├── templates/ ②
│ ├── parts/
└── types/ ⑤

Here is the contents of the entry.shtml entry file for the Blog markup module:

app/modules/markup/blog/entry.shtml
1<!-- #bbinclude "templates/#TEMPLATE#.shtml"
2#bbincludeoptions#="inline=true"
3#MODULE# = "blog"
4#ICON# = "external-link"
5#TARGET# = "_blank"
6#COLUMNS# = "4"
7#LINK-TEXT# = "Read More →"
8#IMAGE-PATH# = 'images/editorial'
9 = ""
10-->
11<!-- end bbinclude -->

In this example, note that a number of variables are defined here. These variables can be overwritten within individual templates, items, and types that are later in the module flow — for example, an particular item might have an image located in a different directory so would redefine #IMAGE-PATH#. Note, however, that if one of those variables was defined in the call to the module earlier in the flow, it would be overwritten with the values found in the entry.shtml entry file for the module. If the call to the module needs to define one of these variables, the default value need to be defined higher in the module flow often in the Pages module entry file.

The #TEMPLATE# variable value, set in the calling file, will be used in the path called by this file and direct the flow of the module to the appropriate template file.

The #MODULE# variable is interesting. Its value is always the name of the module’s enclosing folder — in this case blog. Since all modules are very similar in structure, there’s a Blank Module which can be duplicated and renamed. It is the basis for all modules. To keep this blank module generic enough for this purpose, the internal links are all defined using the #MODULE# variable in place of the hard-coded module name. The Blank module is an attempt to reduce the boilerplate code that’s an unfortunate part of the Code Modules system.

Overview of a Markup Module’s Internal Flow

Overview of a Markup Module’s Internal Flow

Calls within a Markup Module are made in a standardized order with each folder representing a different function.

In the trivial example above:

  • The Template file default.shtml sets the tags that surround the markup: <ul>[call to list]</ul>. The Template file calls the List file.
  • The Lists file default.shtml calls Items twitter.shtml and facebook.shtml in that order.
  • The Item file twitter.shtml defines #TEXT# = 'Twitter' and calls the Type file.
  • The Item file facebook.shtml defines #TEXT# = 'Facebook' and calls the Type file.
  • The Type file default.shtml is: <li>#TEXT#</li>.
  • The returned markup from this module (without white space) is:
    <ul><li>Twitter</li><li>Facebook</li></ul>

Let’s talk about the flow through a module. The flow through the folders of the module is usually standardized. For this next example, let’s assume that the desired template is recent:

entry ⟶ templates/ ⟶ lists/ ⟶ items/ ⟶ types/.

app/modules/markup/blog/
blog/
├── _notes.txt
├── entry.shtml ①
├── items/
│ ├── blank.shtml
│ ├── buns.shtml
│ ├── sausages.shtml ④
│ └── toppings.shtml
├── lists/
│ ├── default.shtml
│ └── recent.shtml ③
├── templates/
│ ├── nav.shtml
│ ├── parts/
│ │ ├── bottom.shtml
│ │ └── top.shtml
│ ├── post.shtml
│ ├── recent.shtml ②
│ ├── teasers-with-images-on-side.shtml
│ ├── teasers-with-images.shtml
│ └── teasers.shtml
└── types/
├── text-list.shtml ⑤
├── nav.shtml
├── single.shtml
├── teasers-with-images-on-side.shtml
├── teasers-with-images.shtml
└── teasers.shtml

The entry.shtml ① file in the entry point to all modules. Calling includes should always use this file to interrogate a module. Variables defined here are used within the rest of the module.

From the entry ①, flow is directed to the templates folder. In this example, there’s a variety of different uses, so there are several template files. Let’s say that the call is for the Recent Blog Posts whose template is recent ②. That template defines the type as text-list and calls lists/recent.shtml ③. The lists/recent.shtml calls the three items in order: sausages ④, buns, toppings. The item files contain the data for each of those blog posts. In this example, the recent template defined the #TYPE# variable as text-list ⑤. types/text-list.shtml plugs the variables defined earlier in the module flow into the text list markup needed for the Recent Blog Posts sidebar. This is repeated for each of the items listed in the recent list.

Module Parts

Files and folders within Markup modules are organized in a standard way to try to reduce the concerns of each separate file. Where possible, markup is separated from items which define variables. Each template may need markup (including, sometimes, a top and bottom). Templates usually call lists of items. The lists define the order of the items. Each item may need to be embodied in markup, usually found in a types file. Because the organization of a module is standardized, the developer knows where to look among a module’s files to find what’s needed.

Templates

entry ⟶ templates/

Here’s what the recent ② template file looks like:

blog/templates/recent.shtml
1<!-- Recent Blog Posts Widget -->
2<div class="card">
3 <h5 class="card-header">
4 Recent Blog Posts
5 </h5>
6 <div class="card-body">
7 <div class="row">
8 <div class="col-lg-12">
9 <ul class="unstyled pl-0">
10<!-- #bbinclude "/markup/#MODULE#/lists/recent.shtml"
11#bbincludeoptions#="inline=true"
12#TYPE# = 'text-list'
13 = ' '
14-->
15<!-- end bbinclude -->
16 </ul>
17 </div>
18<!-- /.col-lg-12 -->
19 </div>
20<!-- /.row -->
21 </div>
22<!-- /.card-body -->
23</div>
24<!-- /.card /.my-4 -->

The top and bottom of the markup are defined here. Each module often has some repeating markup (perhaps <li></li> tags) and markup that appears above and below that repeating section (perhaps <ul></ul>). The template is responsible for the markup that appears above and below the repeating markup for all the blog posts.

The template calls lists/recent.shtml ③ defining the #TYPE# variable as text-list.

Lists

entry ⟶ templates/ ⟶ lists/

The template calls a list, here lists/recent.shtml ③. The list is responsible for calling each item in order. In this example, there is a default list, which would contain all the blog posts, and a recent list, which might only have the last three. In Code Modules, the list file(s) determine which items to include and in what order they should appear.

The blog/lists/recent.shtml calls the individual items -- here twitter.shtml and linkedin.shtml -- in the order that they should appear.

Here’s what the list file ③ looks like:

blog/lists/recent.shtml
1#bbinclude "/markup/#MODULE#/items/sausages.shtml"
2#bbinclude "/markup/#MODULE#/items/buns.shtml"
3#bbinclude "/markup/#MODULE#/items/toppings.shtml"

Although not always the case, lists tend to use BBEdit’s simple include syntax. If the first item needed to define a class "first", then BBEdit’s persistent include syntax would be appropriate defining a variable for the class. Because first (and last) involve ordering, it would be best to define the class in the list rather than in the item itself. The item itself shouldn’t know anything about its order in a list.

Items

Here’s what the sausages item file looks like, with text elided:

blog/items/sausages.shtml
1<!-- #bbinclude "/markup/#MODULE#/types/#TYPE#.shtml"
2#bbincludeoptions#="inline=true"
3#TITLE# = 'Are Hot Dogs Sausages?'
4#TEASER# = 'Instinctively, you know that they are. But there’s an unmistakable difference between a sausage sandwich and a hot dog. So what gives?'
5#URL-EXT# = 'https://difference.guru/difference-between-a-hot-dog-and-a-sausage/'
6#URL# = 'blog-sausages.html'
7#NAV-NAME# = 'Sausages'
8#IMAGE# = 'Sausage_Assortment_on_a_Grill-40-1430x760.jpg'
9#ALT# = 'Sausage Assortment on a Grill, photo by Hasmik Ghazaryan Olson via Unsplash.'
10#DATE-SLUG# = 'Wednesday, August 11, 2021'
11#TEXT# = '<p>Bacon ipsum dolor amet brisket salami kevin sausage ... pancetta beef pork.</p>'
12-->
13<!-- end bbinclude -->

An individual item file is usually about data. It contains all its information in variables.

There’s also usually a blank.shtml file in the items/ folder. This is there to provide a skeleton for new items, together with any helpful instructions contained in a #COMMENT# variable.

blog/items/blank.shtml
1<!-- #bbinclude "/markup/#MODULE#/types/#TYPE#.shtml"
2#bbincludeoptions#="inline=true"
3#TITLE# = ''
4#TEASER# = ''
5#URL# = ''
6#URL-EXT# = ''
7#NAV-NAME# = ''
8#IMAGE# = ''
9#ALT# = ''
10#DATE-SLUG# = ''
11#TEXT# = ''
12#COMMENT# = 'DATE-SLUG is in the form Monday, August 9, 2021. TEXT should be formatted as HTML within p tags. NAV-NAME is the link text for navigation, i.e. Sausage. ICON is external-link by default but can be overridden. IMAGE-PATH can be overridden.'
13-->
14<!-- end bbinclude -->

Types

In the first line, the item calls the types/ folder and, in this case, a file that is named based on the #TYPE# variable, here text-list

Types files contain a skeleton of the actual markup that will be used that accepts the variables defined earlier in the chain.

The text-list type file looks like this:

blog/types/text-list.shtml
1<li class="mb-3">
2 <a href="#URL#">
3 <small>
4 #DATE-SLUG#
5 </small>
6 <br />
7 #TITLE#
8 </a>
9</li>

The type file doesn’t have to use all the variables defined in the item file.

Since all the Recent Blog Posts sidebar widgets pass through this Type file, a change to the markup here will ripple everywhere within the site that uses it.

Notes

Each module has another file that we haven’t talked about. It’s the _notes.txt file. I put any specific documentation about how to use a module in this file. I also copy and paste all the persistent includes which call the module. This makes it easy to see what “promises” the module must satisfy. It also means helps to copy, paste, and alter out of the _notes.txt file and into a new calling file.

Recap

To recap, for most modules, the template will define the markup that’s at the top and bottom of what will be returned. The list defines the order of items. Each item contains the data for that item. And the type file contains the markup for a single item.

If a new blog post needs to be included, then an item is created and the contents of the blank.shtml item file are pasted in. From there, it’s a matter of filling out the variable values in the new item file and then including that item file in the list files for default and recent.

Key Point

The key point is that adding the new blog post item doesn’t require any knowledge about the differences in markup between Blog Home 1 or Blog Home 2 or the sidebar or the individual blog posts found throughout the site. That information is coded into the module and the maintainer doesn’t need to think about it when adding a new item. Abstracting away that complexity is one of the main purposes of the Code Modules system.

Modules can be flexible. They can deliver different output using the same data as need arises. And modules can use the data contained in another module by calling it in a defined way. In the case of the Blog module, individual recent blog posts are also included in the navigation for the site. Navigation is found on the top of each page, but also in different forms on the Sidebar page and on the 404 page. The Nav module calls the Blog module to get the information it needs to generate navigation-related markup in three different styles. Again, the maintainer doesn’t need to think about this or, indeed, even know about it. It’s already coded into the module and, when the site is rebuilt, it happens automatically.