15.00 One page per book

Table of contents

Edit this page

This article tells you how to create one page for each book.

The portfolio page is looking great. But if you click through on one of the covers, you get an empty page.

You need to write code that automatically generates one page per book. If you look back to the Amazon example, earlier, you’ve done the list page and you’re now writing the single-book show page.

Amazon screenshots

Open the file in _layouts called book_template.html, and make it use the template you’ve used for all the other pages so far by pasting the following right at the top of the file. Delete the TODO comment in the process.

---
layout: default
---

Learn more later

  • You are using an adapted Jekyll plugin to generate all the pages-per-book. The authors of the plugin have written docs which you can read later, though we have edited their plugin substantially to tailor it for Day of Code. Within your codebase, review _config.yml, where you’ll see the configuration line page_gen-dirs: true, and you’ll see the edited plugin code itself in the _plugins/data_page_generator.rb, as instructed in their docs.

Now if you click through from a cover on the portfolio page, you’ll not get a missing link, but since your book_template.html page is empty, there’s not much to see:

A boring blank page with just nav links showing

Let’s add some code.

Build the book template

The code at _plugins/data_page_generator.rb runs when you start the Jekyll server. It uses Ruby programming to iterate through the data source and create multiple HTML files using the book_template.html page as a template. Jekyll provides the page variable to access the JSON data store in _data/processed_books.json. The data structure in the JSON file is like this:

1
2
3
4
5
6
7
8
9
10
[
  {
    "title":      "Solid State Physics",
    "isbn":       "9781466512320",
    "amz_uk_url": "http://www.amazon.co.uk/gp/product/1466512326",
    "image_path": "9781466512320.jpg",
    "author":     "Javier E. Hasbun and Trinanjan Datta"
    <!-- etc -->
  }
]

You get data out of that structure by using the keys: page.title, page.isbn, page.author and so on.

Copy and paste the following code into book_template.html underneath the frontmatter (the --- bit).

<header class="portfolio-header">
  <h1 class="secondary">• Coming soon •</h1>
</header>

<main class="portfolio-page">
  <figure>
    <img class="cover--large" src="/images/covers/{{page.isbn}}.jpg" alt="Cover of ISBN {{page.isbn}} {{page.title}}"/>
  </figure>
  <section>
    <p class="metadata">
      {{page.series}}
      {{page.series_number}}
    </aside>
    <h1>{{page.title}}</h1>
    <p>{{page.subtitle}}</p>
    <h2>{{page.author}}</h2>
    <p>{{page.blurb}}</p>

    {% if page.reviews.size > 0 %}
      <hr/>
      <p><span class="massive"></span>{{page.reviews}}</p>
    {% endif %}

    <ul class="metadata">
      <li>
        <span>ISBN</span>
        {{page.isbn}}
      </li>
      {% if page.pub_date.size > 0 %}
        <li>
          <span>Published</span>
          {{page.pub_date | date: "%d %b %Y"}}
        </li>
      {% endif %}

      {% if page.gbp_price%}
        <li>
          <span>Price</span>
          ${{ page.usd_price }} / £{{ page.gbp_price }}
        </li>
      {% endif %}

      {% if page.page_count.size > 0 %}
        <li>
          <span>Pages</span>
          {{page.page_count}}
        </li>
      {% endif %}

      {% if page.format.size > 0 %}
      <li>
        <span>Format</span>
        {{ page.format }}
      </li>
      {% endif %}
    </ul>

    <p class="metadata">{{page.subject}}</p>

    <h3>Buy {{page.title}}</h3>
    <ul class="shops">
      <li>
        <a class="bookstore" rel="noreferrer" target="_blank" href="{{ page.wordery_url }}">Wordery</a>
      </li>
    </ul>
  </div>
</main>

Review the pages

Click through from any cover on the portfolio page and you should now see your book data, one page per book.

A screenshot of a really nicely laid out book page, with pricing, subject metadata, a well-designed cover, the blurb, the author names and the series, too, with a review quote.

Learn more later

  • You can see the JSON data created from ONIX in _data/processed_books.json.
  • You can see the code that created it in the lib folder.
  • Track down the element and class names referenced here, such as metadata and portfolio-header, in the main.css file, to see how they’re defined.

Do more later: Add more stores

See if you can add more links to the page to more retailers. The code below will help you.

<li><a class="bookstore" rel="noreferrer" target="_blank" href="{{ page.waterstones_url      }}">Waterstones    </a></li>
<li><a class="bookstore" rel="noreferrer" target="_blank" href="{{ page.foyles_url           }}">Foyles         </a></li>
<li><a class="bookstore" rel="noreferrer" target="_blank" href="{{ page.book_depository_url  }}">Book Depository</a></li>
<li><a class="bookstore" rel="noreferrer" target="_blank" href="{{ page.wh_smith_url         }}">WHSmith        </a></li>
<li><a class="bookstore" rel="noreferrer" target="_blank" href="{{ page.blackwells_url       }}">Blackwells     </a></li>
<li><a class="bookstore" rel="noreferrer" target="_blank" href="{{ page.oxfam_url            }}">Oxfam          </a></li>
<li><a class="bookstore" rel="noreferrer" target="_blank" href="{{ page.amz_uk_url           }}">Amazon UK      </a></li>
<li><a class="bookstore" rel="noreferrer" target="_blank" href="{{ page.amz_us_url           }}">Amazon US      </a></li>
<li><a class="bookstore" rel="noreferrer" target="_blank" href="{{ page.amz_ca_url           }}">Amazon CA      </a></li>
<li><a class="bookstore" rel="noreferrer" target="_blank" href="{{ page.amz_de_url           }}">Amazon DE      </a></li>
<li><a class="bookstore" rel="noreferrer" target="_blank" href="{{ page.amz_br_url           }}">Amazon BR      </a></li>
<li><a class="bookstore" rel="noreferrer" target="_blank" href="{{ page.amz_mx_url           }}">Amazon MX      </a></li>
<li><a class="bookstore" rel="noreferrer" target="_blank" href="{{ page.amz_fr_url           }}">Amazon FR      </a></li>
<li><a class="bookstore" rel="noreferrer" target="_blank" href="{{ page.amz_es_url           }}">Amazon ES      </a></li>
<li><a class="bookstore" rel="noreferrer" target="_blank" href="{{ page.amz_jp_url           }}">Amazon JP      </a></li>
<li><a class="bookstore" rel="noreferrer" target="_blank" href="{{ page.amz_in_url           }}">Amazon IN      </a></li>
<li><a class="bookstore" rel="noreferrer" target="_blank" href="{{ page.kobo_url             }}">Kobo           </a></li>
<li><a class="bookstore" rel="noreferrer" target="_blank" href="{{ page.infini-beam_url      }}">Infinibeam     </a></li>
<li><a class="bookstore" rel="noreferrer" target="_blank" href="{{ page.google_play_url      }}">Google Play    </a></li>
<li><a class="bookstore" rel="noreferrer" target="_blank" href="{{ page.hive_url             }}">Hive           </a></li>
<li><a class="bookstore" rel="noreferrer" target="_blank" href="{{ page.booktopia_url        }}">Booktopia      </a></li>
<li><a class="bookstore" rel="noreferrer" target="_blank" href="{{ page.barnes_and_noble_url }}">Barnes & Noble </a></li>
<li><a class="bookstore" rel="noreferrer" target="_blank" href="{{ page.worldcat_url         }}">Worldcat       </a></li>
<li><a class="bookstore" rel="noreferrer" target="_blank" href="{{ page.books_a_million_url  }}">Books A Million</a></li>
<li><a class="bookstore" rel="noreferrer" target="_blank" href="{{ page.book_finder_url      }}">Book Finder    </a></li>

Click through to see if some of the retailers have your book in stock.

Do more later 2: schema.org data

You can improve the SEO of your webpage by including structured data as recommended by Schema.org. Below is some code you can add.

<!-- add to the top of book_template.html, underneath the front matter -->
{%
  include structuredData.html
  title = page.title
  author = page.author
  isbn = page.isbn
  pub_date = page.pub_date
  usd_price = page.usd_price
  gbp_price = page.gbp_price
  url = page.url
%}

<!-- Add to a new file called structuredData.html, in the _includes folder -->
<script type="application/ld+json">
{
  "@context":"http://schema.org",
  "@type":"Book",
  "@id": "http://silveroakpress.com/{{ include.isbn }}",
  "name" : "{{ include.title }}",
  "author": {
    "@type":"Person",
    "name":"{{ include.author }}"
  },
  "url" : "{{ include.url }}",
  "workExample" : [{
    "@type": "Book",
    "@id": "http://silveroakpress.com/{{ include.isbn }}",
    "isbn": "{{ include.isbn }}",
    "datePublished": "{{ include.pub_date }}",
    "bookFormat": "http://schema.org/Paperback",
    "potentialAction":{
    "@type":"ReadAction",
    "target":
      {
        "@type":"EntryPoint",
        "urlTemplate":"http://www.barnesandnoble.com/s/{{include.isbn}}",
        "actionPlatform":[
          "http://schema.org/DesktopWebPlatform",
          "http://schema.org/IOSPlatform",
          "http://schema.org/AndroidPlatform"
        ]
      },
      "expectsAcceptanceOf":{
        "@type":"Offer",
        "Price":"{{include.usd_price}}",
        "priceCurrency":"USD",
        "eligibleRegion" : {
          "@type":"Country",
          "name":"US"
        },
        "availability": "http://schema.org/InStock"
      }
    }
  }]
}
</script>

Then look in the Inspector to see the results.

Do more later 3: Conditionals

Amend the HTML code in book_template.html so that the banner at the top of the page changes according to the pub date:

  {% assign todays_date = "now" | date: "%Y%m%d" %}

  {% if page.pub_date_iso > todays_date %}
    <h1 class="secondary">• Coming soon •</h1>
  {% else %}
    <h1 class="secondary">• Recently published •</h1>
  {% endif %}

What you’ve learned

  • You can use other people’s open source code to perform certain tasks, such as you’ve done here to generate the static pages
  • You call methods on the page variable, which are named using the keys in the JSON data store