Writer's Guide
Hugo quirks, info, and totally awesome Caitlin customizations:
Links – Links won’t work in master build without a forward slash at the end
Aliases – When you move a page, add a redirect so that links aren’t broken.
TOC Page Names – Provide a shortened page name to appear in the TOC. Descriptive name still appears in search results.
Syntax Highlighting – Link to relevant Hugo doc.
SEO – Couple SEO best practices
Notices – Highlighted notes like tips, billing, plain notes, etc.
Expandables – Various click-to-expand elements.
Field List – Styling for field lists (makes title blue, indents). Doesn’t just have to be fields.
Content Reuse – How to reuse entire page contents or sections of a page. That way if it changes you only have to update once.
Portal Icons – How to use inline icons from the SVG sprites file (used in portal).
Definition Lists – If you’re using DLs and the content gets a bit complicated, markdown can’t handle it.
Page-Level Styles – Shortcode to add CSS for a specific page.
Page-Level JavaScript – Shortcode to add JS for a specific page.
Complex Tables – How to write tables as a nested list, style those tables, row spans/column spans.
Links
When creating links to internal content, make sure you end with a forward slash /
. Links without forward slashes work on your local server, but do not work on docs.packetfabric.com.
For example: [Create a Port](/ports/create/port/)
Exception
If you are linking to an anchor within a page, don’t end with a slash: [Create a Port](/ports/create/port/#next-steps)
[Create a Port](/ports/create/port/#next-steps)
Create a Port
Aliases
If you move a page, you should add an alias to that page with its previous filepath. This will ensure that any links that someone might have to that page don’t result in a 404 page.
You add the alias in the page metadata:
aliases:
- /cloud/dedicated/google/google/
TOC Page Names
Sometimes a descriptive name for a page is overly long and makes the side-bar TOC difficult to scan.
However, if we shorten the name to something generic, it becomes a problem when that page appears in search results.
You can get around this using the menuTitle
page param.
title: "Create a Google Dedicated Interconnect Connection"
menuTitle: "Create a Dedicated Connection"
Highlight
This isn’t a custom shortcode, but use the Hugo “highlight” shortcode for code blocks: https://gohugo.io/content-management/syntax-highlighting/#highlight-shortcode
SEO
Some things that can help SEO:
- Use h1/h2/h3 headers (should already be doing that).
- Descriptive file names for images.
- Having alt text for an image:

(not the best example of descriptive file name)
Notices
{{< notice note >}}**NOTE:** {{< /notice >}}
{{< notice tip >}}**TIP:** {{< /notice >}}
{{< notice info >}}Important info {{< /notice >}}
{{< notice billing >}}Billing info {{< /notice >}}
To be added: “Warning” note
Expandables
Expandable Button
Use this for hiding/expanding pieces of content within a section.
{{< expandable "Text you want on button" >}}
Inner text
{{< /expandable >}}
For an example, see Create a Port.
Expandable Section
Use this for hiding/expanding full sections of content.
Must be preceeded by a header (h1, h2, h3, etc) – h4 seems to look best.
Header
Header 2
#### Header
{{< expandable_section >}}
Section text
{{< /expandable_section >}}
For an example, see Create Multiple Ports.
FAQ
Yet another expandable thing!
How do I make an expandable FAQ?
faq
shortcode.
How do I make an expandable FAQ?
{{< faq >}}
You do this.
{{< /faq >}}
Field List
Use this as a helper for styling field names on pages. It makes the field name bold and blue, and indents the content.
Use h5 headers.
Field One
Text text text
Field Two
Text text text
<div class="field-list">
##### Field One
Text text text
##### Field Two
Text text text
</div>
For an example, see Create a Port.
Content Reuse
This can be used to pull in the entire contents of page or just sections of a page.
To pull in a full page:
{{< reuse path="interfaces/pages" >}}
../images
) won’t be pulled in. You’ll need to provide a full path.To pull in a portion of a page, you need to provide the starting point “d1” and ending point “d2”:
- The page is processed as raw HTML and needs to be complete, so both of your d1 and d2 parameters need to reflect the rendered HTML (use your browser’s inspector tool to grab this)
- The snippets need to have enough to make them unique. For example, don’t use “
<p>The
” because there’s a good chance that appears multiple times. Add enough to the search string to make it unique. - These parameters are placed into a RegEx search string, so you need to be careful with the following characters:
\ ^ $ . | ? * + ( ) [ {
. Use a backslash to escape special characters.
{{< reuse path="/interfaces/pages" d1="<h4 id=\"traffic\"" d2="reuseEnd-->" >}}
In the example above, my d2
parameter is an HTML comment I added to the source. In this case, the end of my raw HTML was a table within a div, which would require a very long string to be unique.
Also note that I escaped the "
in traffic
– I guess Hugo doesn’t like nested quotation marks.
Look at epl/pages.md
for an example of this shortcode being used.
Portal icons
This is a shortcode for displaying SVG icons that are used in the portal.
Use an inspector tool to find the name of the icon and specify which color it should be (currently have styling for red, green, and blue).
Note:
- This is only for small icons - the big “Create” button is its own thing.)
- When supplying the icon name, drop the “icon-” prefix. For example, enter
delete
foricon-delete
. - The
title
is optional. Anything you put for the title will appear as a tooltip when hovering over the icon. - The
class
param is optional. Can use this for tweaking in certain circumstances. Right now we only havelarge
defined in the site CSS (makes it 24px instead of 20). But this can also be helpful if you’re using a page-level CSS block.
{{< portal_icon color="red" icon="delete" title="Click to delete" class="large" >}}
Definition Lists
If you are using a definition list, and one of the <dd>
elements is more complicated (e.g. has an unordered list), you need to do two things:
- Precede it with an empty dd (
:
) - Wrap it in custom HTML.
Then custom.js will do the rest.
I tried using a shortcode for this but it couldn’t accurately place notices in list items.
dt text
:
<dd class="dd-item">
* stuff
</dd>
Page-Level Styles
There might be situations in which you need to style something specific to a single page. To do that, you can use the style
shortcode to add a CSS block to the page.
{{< style >}}
th {
background: hotpink;
color: black;
}
{{< /style >}}
Page-Level JavaScript
Similarly, there might be occassions when you need to use a bit of JS.
For this, you can use the cust_js
shortcode.
When compiled, the shortcode wraps everything in the cust-js
block inside a “custJS” function. This function is then called after all the other custom Javascript runs.
For example, this:
{{< cust_js >}}
$('#six').appendTo( $('#five') )
{{< /cust_js >}}
Becomes this:
function customJS() {
$('#six').appendTo( $('#five') );
}
So if you just have something simple, write it directly. If you have something more complicated and need to write out your own functions, then you need to call the function yourself at the bottome of the cust-js
block, so that it will be executed when the wrapping function runs, e.g:
{{< cust_js >}}
funcion six() {
$('#six').appendTo( $('#five') );
};
six();
{{< /cust_js >}}
Not the prettiest thing, but whatever.
Complex Tables
Simple markdown tables can’t have children (you can’t have an unordered list in a table), and can get complicated really fast.
I wrote some JS to allow us to write out the table as a nested list. This is mostly just helpful for complex tables.
It has the following components:
-
You need to wrap it in
<div class="mdtable">
or themd_table
shortcode. -
The first bullet points are what goes in the table header.
-
Begin every row with some sort of content. I use “row” in the example below, but you can number them or use a string. Just don’t leave it empty.
IMPORTANT:
Something happens in Hugo when you nest ol > li > div
(probably also in ul
as well). Will submit a bug report if it’s still there after updating versions.
However, divs rendered through shortcodes work fine. So I created a shortcode that can be used with instead of <div class="mdtable">
.
If using the shortcode, you can add classes and col-w (see below) the same way you would with the div.
{{< md_table class="headless" col-w="20 80" >}}
* header
* list list
* list again
* r
* list list
* list again
* r
* list list
* list again
{{< /md_table >}}
The following examples all use the div, because I didn’t initially plan on having to use a shortcode.
<div class="mdtable">
* Header row
* Column 1
* Col2
* Last col
* Row 1
* Thing in first cell
* Thing in second cell
* child list in second cell
* child list in second cell
* Third cell
Third cell second paragraph
* Row 2
* Blah
* Blah
* Blah
</div>
-
Header row
- Column 1
- Col2
- Last col
-
Row 1
-
Thing in first cell
-
Thing in second cell
- child list in second cell
- child list in second cell
-
Third cell
Third cell second paragraph
-
-
Row 2
- Blah
- Blah
- Blah
There are some variations:
Border Table
Add the border
class to the <div class="mdtable">
element to add borders in table rows:
<div class="mdtable border">
* Header row
* Column 1
* Col2
* Last col
* Row 1
* Thing in first cell
* Thing in second cell
* child list in second cell
* child list in second cell
* Third cell
Third cell second paragraph
* Row 2
* Blah
* Blah
* Blah
</div>
-
Header row
- Column 1
- Col2
- Last col
-
Row 1
-
Thing in first cell
-
Thing in second cell
- child list in second cell
- child list in second cell
-
Third cell
Third cell second paragraph
-
-
Row 2
- Blah
- Blah
- Blah
No Header Table
Add the headless
class to the <div class="mdtable">
element to hide the header row:
<div class="mdtable border headless">
* Header row
* Column 1
* Col2
* Last col
* Row 1
* Thing in first cell
* Thing in second cell
* child list in second cell
* child list in second cell
* Third cell
Third cell second paragraph
* Row 2
* Blah
* Blah
* Blah
</div>
-
Header row
- Column 1
- Col2
- Last col
-
Row 1
-
Thing in first cell
-
Thing in second cell
- child list in second cell
- child list in second cell
-
Third cell
Third cell second paragraph
-
-
Row 2
- Blah
- Blah
- Blah
Column Width
Add a col-w
attribute to <div class="mdtable">
if you want to set column width.
<div class="mdtable headless" col-w="20 80">
In the example above, the first column width is 20% and the second is 80%.
Spans
Can do column spans OR row spans. Currently cannot have both in the same table.
- Add class
rowspan
to<div class="mdtable">
if you are using row spans. Addcolspan
for column spans. - For cells that will be merged into the span, enter an empty bullet point.
IMPORTANT:
Put a couple blank spaces in your empty bullet point. Sometimes Hugo/markdown will just strip out empty list items altogether.
Row Spans
<div class="mdtable border rowspan">
* Header row
* column1
* column2
* column3
* column4
* row
* one-one
* one-two
* one-three
* one-four
* row
* two-one
* two-two
* two-three
* two-four
* row
* three-one
*
* three-three
* three-four
* row
* four-one
*
* four-three
*
* row
* five-one
* five-two
* five-three
*
</div>
-
Header row
- column1
- column2
- column3
- column4
-
row
- one-one
- one-two
- one-three
- one-four
-
row
- two-one
- two-two
- two-three
- two-four
-
row
- three-one
- three-three
- three-four
-
row
- four-one
- four-three
-
row
- five-one
- five-two
- five-three
Column Spans
<div class="mdtable border colspan">
* Header row
* column1
* column2
* column3
* column4
* row
* one-one
*
*
* one-four
* row
* two-one
* two-two
* two-three
* two-four
* row
* three-one
*
*
*
* row
* four-one
* four-two
* four-three
* four-four
* row
* five-one
* five-two
*
* five-four
</div>
-
Header row
- column1
- column2
- column3
- column4
-
row
- one-one
- one-four
-
row
- two-one
- two-two
- two-three
- two-four
-
row
- three-one
-
row
- four-one
- four-two
- four-three
- four-four
-
row
- five-one
- five-two
- five-four