Write data from a shortcode to a file

I have a shortcode that needs to write some data to an external file. Is that possible? How?

The application is embedding quizzes for an education site. The shortcode is used to specify the question and correct answer with an appropriate call to a javascript function. The correct answer needs to be exported to a process running on a server so answers aren’t embedded in the site where students can see them and so their answers can be recorded. Being able to keep the question and correct answer together in the site source code alleviates a bunch of management/coordination concerns.

Thanks for any pointers.

When building a site, all files are created within publishDir (typically public). You cannot generate files outside of this directory.

It sounds like you want to create data from markup/code. Would you consider creating the markup/code from data instead?

Create a JSON, YAML, or TOML file with all of the questions, possible answers, correct answer, and a unique ID for each question. You can use this on the server side to validate responses.

{
  "000001": {
    "question": "What color is the sky?",
    "possible_answers": {
      "a": "Green",
      "b": "Red",
      "c": "Blue"
    },
    "correct_answer": "a"
  },
  "000002": {
    "question": "Is the earth flat?",
    "possible_answers": {
      "a": "Yes",
      "b": "No"
    },
    "correct_answer": "b"
  }
}

Then within your Hugo project, place the file in the data/ directory and pull your question into the shortcode using .Site.Data.

markdown:

{{< question id="000001" >}}

generated html:

<p>What color is the sky?</p>
<form id="question-000001">
  <input type="radio" id="a" name="answer" value="a">
  <label for="a">Green</label>
  <input type="radio" id="b" name="answer" value="b">
  <label for="b">Red</label>
  <input type="radio" id="c" name="answer" value="c">
  <label for="c">Blue</label>
</form>

layouts/shortcodes/question.html:

{{- $question_id := "" -}}

{{- with .Get "id" -}}
  {{- $question_id = . -}}
{{- else -}}
  {{- errorf "The '%s' shortcode requires a named parameter (id), the ID of the question. See %s" .Name .Position -}}
{{- end -}}

{{- with $item := index .Site.Data.questions $question_id  -}}
  {{- $question := index $item.question -}}
  {{- $possible_answers := index $item.possible_answers -}}
  <p>{{ $question }}</p>
  <form id="question-{{$question_id}}">
    {{- range $k, $v := $possible_answers }}
      <input type="radio" id="{{ $k }}" name="answer" value="{{ $k }}">
      <label for="{{ $k }}">{{ $v }}</label>
    {{- end }}
  </form>
{{- else -}}
  {{- errorf "The '%s' shortcode was unable to find a question with ID '%s'. See %s" .Name $question_id .Position -}}
{{- end -}}

And this could be modified to generate a single form with multiple questions, invoked with something like:

{{< quiz >}}
000001
000002
{{< /quiz >}}

This way you have all of the questions and answers in one place, under version control, and you are keeping the answers out of the publishDir.

2 Likes

A+ answer, @jmooring! Thank you! The only difficulty I see with this is that questions will sometimes involve a block of HTML or Markdown that needs to be squeezed into a single Json string. Ah… I see that YAML supports multi-line strings. Good to go!

Thanks!

Interesting exercise. Some people like crossword puzzles. I, on the the other hand…

git clone --single-branch -b hugo-forum-topic-27860 https://github.com/jmooring/hugo-testing hugo-forum-topic-27860
cd hugo-forum-topic-27860
hugo server

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.