Jekyll-Markdown: Add voting to a Blog Post
web jekyll web markdown azurefunction survey voting state
Jekyll-Markdown is compiled and deployed as a static web site. So how can you add voting functionality to a blog post?
One approach is to use an external service, such as Azure Functions, to handle the voting logic. This way, you can keep your Jekyll site static while still providing dynamic functionality.
Here’s a high-level overview of the steps involved:
- Voting Options: Define the voting options you want to present to users in a yaml file in the
_datafolder of your Jekyll site. This makes it easy to manage and update the options.- Structure of the yml file is name and value pairs.
- Create an Azure Function: This function will handle the voting logic, including recording votes and getting tallies.
- Integrate the Function with Your Blog: Use JavaScript to call the Azure Function from your blog posts.
- You can create a simple voting interface as an included HTML page
- This page iterates through the list of voting options from the yaml file and displays them as buttons or links.
- Display Voting Results: After a user votes, you can update the UI to show the current vote tally without requiring a page refresh upon submitting a vote
- Include the voting interface … in your blog posts using Jekyll’s include functionality.
- Store Voting Data: Use an Azure Blob Storage to store voting data.
- Each vote can be recorded in a blob, and the Azure Function can read from and write to this blob as needed.
- Configure to only show votes if tally is non zero; alternative, only show votes if voted locally.
-
Implement Voting Logic: Use Javascript in the blog post where the voting occurs to restrict votes to one per user using LocalStorage to track if a user has voted.
- Actually implement an automatic page refresh.
- For development purposes Include a Powershell script to clear the votes in the Blob Storage
- and Javascript to to clear the localStorage data of voting, so that can send another vote.
A Sample Voting Implementation … try it
Votes Survey
Q. What do you want to do?
(Please Select one. Votes shown.)
By following the steps as above and detailed below, you can add a voting feature to your Jekyll blog posts while keeping the site static and fast. In this documentation, I provide a sample implementation of such a voting system using Jekyll and an Azure Function running locally, and using anAzure Blob Storage.
Repository: djaus2/VotesJekyllMarkdown
- Clone and use this repository as a starting point for your own implementation.
- You will need to apply some configuration settings to make it work for your own Azure Function and Blob Storage.
- Note this is not yet complete. Please leave feedback in the repository!
1. A Sample .yml page for voting options
- - 'option1'
- 'The quick brown'
- - 'option2'
- 'Jumps over the lazy dog'
- - 'option3'
- 'To be, or not to be:'
- - 'option4'
- 'That is the question'
- - 'option5'
- 'En un lugar de la Mancha'
- - 'option6'
- 'Once upon a time'
_data/votingoptions.yml
2. The Azure Function
See the code repository djaus2/JekyllBlogVoting for the Azure Function project that handles the voting logic. This function will receive votes from the blog post, update the vote counts in Azure Blob Storage, and return the current tallies when requested.
- Notes wrt the Azure Function:
- When deployed to Azure _(later) you need the Function URL and the Function Key to call it from the blog post.
- To get the function key, which IS NOT an App key, go to the Azure Portal, navigate to your Function App - Overview, select (click on) the specific function (from Functions toward bottom), and then find “Function Keys” near top.
- When deployed to Azure (later) but running the site locally, need to set CORS access to allow localhost requests.
- In the Azure Portal in the Function search for CORS and add
http://localhost:4000(or whatever port) to the allowed origins.
- In the Azure Portal in the Function search for CORS and add
- When deployed to Azure _(later) you need the Function URL and the Function Key to call it from the blog post.
3. The HTML Include file for voting
<div class="survey" data-id="{{ include.id | default: 'The quick brown' }}" data-ns="{{ site.title | default: 'option1' | slugify }}" data-api="{{ include.api | default: '' }}" data-key="{{ include.key | default: page.url }}" data-code="{{ include.code | default: '' }}">
<h2>Votes Survey</h2>
<h3>Q. What do you want to do?</h3>
<i>(Please Select one. Votes shown.)</i>
<div class="survey-options">
<ul>
{% assign options = site.data.voteoptions %}
{% if options %}
{% for pair in options %}
{% assign opt = pair[0] %}
{% assign label = pair[1] %}
<li><button class="survey-opt" type="button" data-opt="{{ opt }}"><span class="survey-count" aria-hidden="true"></span> {{ label }}</button></li>
{% endfor %}
{% endif %}
</ul>
</div>
<div class="survey-status" aria-live="polite"></div>
</div>
<script src="{{ '/assets/clientId.js' | relative_url }}" defer></script>
<script src="{{ '/assets/js/survey.js' | relative_url }}" defer></script>
<style>
Part of the file _includes/votes.html
Note that it iterates through the name-value pairs in the .yml file. The value for each is displayed as a button. The name is what is submitted and stored as the vote.
4. The Name-Value Pairs in display loop
{% for pair in options %}
{% assign opt = pair[0] %}
{% assign label = pair[1] %}
In the code above, the loop iterates through each pair in the options array, assigning the first element of the pair to opt which is what is sent to the backend end code and services. The second element in the pair is the label and is what is displayed on the buttons. These are defined in the .yml file except that the label has tallies prepended to it dynamically by the backend code (if non-zero).
5. Including the Voting in a Blog Post
{% include votes.html
id="vote_survey"
api="https://THE_AZURE_FUNCTION_NAME.azurewebsites.net/api/THE_SPECIFIC_API"
code="AZURE_FUNCTION_KEY"
key=page.url %}
Including the voting interface in a blog post
See notes above wrt specific Function key.
Note: CAPITALIZED parts need to be replaced with your actual Azure Function details:
- When you create the Azure Function, the project name replaces THE_AZURE_FUNCTION_NAME above.
- THE_SPECIFIC_API is the specific function you create to handle the voting as a separate page in the project.
- Make sure that you use the Function Key not one of the others.
6. Store Voting Data
Create an Azure Blog Storage account to store the voting data. The Azure Function will read from and write to this blob as needed. Each vote can be recorded in a blob, and the Azure Function can read from and write to this blob as needed.
See the repository djaus2/VotesJekyllMarkdown for how to create the Blob Storage using Azure Cli.
OR
MS Learn: Create an Azure storage account
7. Implement Voting Logic
See JavaScript files in the repository djaus2/JekyllBlogVoting in /assets/js/survey.js and /assets/js/getClientId.js that handle the voting logic, including restricting votes to one per user using LocalStorage to track if a user has voted.
8. For Development Purposes, Clearing Votes
There is a PowerShell script for development purposes to clear the blob storage votes.
Repository/BlogFiles/scripts/resetCounter.ps1
.\scripts\resetCounter.ps1 -Secret "ADMIN_SECRET" -Extent all -Code "FUNCTION_KEY"`
PowerShell script to clear votes in Blob Storage
- Replace
ADMIN_SECRETwith the admin secret you set in the Azure Function configuration. - Replace
FUNCTION_KEYwith the function key for the voting function.
There is also a button here for development purposes to clear votes from localStorage from the browser but NOT to clear the votes from the Azure Blob Storage. This enables you to retest voting from the same browser. Both would not be made available in production.
{% include clear-votes.html %}
The button to clear localStorage votes
This is included in the blog post where the voting.html is included.
<button type="button" class="btn btn-warning" id="clear-votes-btn">
Clear Votes in Local Storage (Can vote again!)
</button>
<script src="/assets/js/clear-votes.js" defer></script>
_include/clear-votes.html include file
Conclusion
So a static web ite like Jekyll-Markdown can have dynamic voting functionality by leveraging Azure Functions and Blob Storage. This approach keeps the site fast and static while still providing interactive features for users.
2Dos:
- Detailed list of configuration setting and steps to deploy the Azure Function and Blob Storage and where to place them.
- Deployment of the Azure Function to Azure.
| Topic | Subtopic | |
| < Prev: | AthStitcher | Features not yet included |
| This Category Links | ||
| Category: | Web Sites Index: | Web Sites |
| < Prev: | Jekyll | Equations using Latex |