Help with shortcode passed arguments

I am trying to create a short code where I pass URLs and to a video template. I need to pass the URL to the src attribute but the video’s type to the type attribute(s) don’t necessarily need to be passed in as arguments, they can be stored as fixed values. I am able to range through my URLs but I’m stuck on how to simultaneously get the right type attribute into the loop. I’m sure I’m missing something simple here, but I’m at a loss…

In my case I want to pass in the URLs in a specific order (webm, mp4) and I need their type attributes to match.

Here is my shortcode template:

{{ $class := .Get "class" }}
{{ $webm := .Get "webm" }}
{{ $mp4 := .Get "mp4" }}
{{ $format := slice $webm $mp4 }}
{{ $type := slice "webm" "mp4" }}

<video controls class="{{ $class }}">
  {{ range $format }}

  <source 
	type="video/{{ $type }}"
	src="{{ . }}"
	>
  {{ end }}

</video>

Here is my short code:

{{< video 
		webm="https://my-webm-video.webm"
    mp4="https://my-mpfour-video.mp4"
    class="video"
>}}

Desired output:

<video controls="" class="video">
 <source type="video/webm" src="https://my-webm-video.webm">
 <source type="video/mp4" src="https://my-mpfour-video.mp4">
</video>

Thanks for the guidance and advice

Where are the video files located?

  • Page bundle?
  • Assets directory?
  • Remote?
  • Other?

Is the base name the same for each format?

my-video.mp4
my-video.webm

Will both files reside in the same directory?

They are hosted remotely on Cloudinary. And look something like this:

https://res.cloudinary.com/directory/video/upload/q_auto,vc_vp9/v123456789/another-directory/my-webm-video.webm

So, in the shortcode, I pass the entire URL copied manually from my dashboard there.

OK, but will both formats have the same path (excluding the filename)?

https://res.cloudinary.com/directory/video/upload/q_auto,vc_vp9/v123456789/another-directory/basename.webm

https://res.cloudinary.com/directory/video/upload/q_auto,vc_vp9/v123456789/another-directory/basename.mp4

@jmooring

Please forgive, I misread your question. Both formats will have the same URL except the portion /q_auto,vc_vp9/ That is where they would differ slightly

I’d do something like…

markdown

{{< video
  mp4="https://example.org/shared/samples/quickstart.mp4"
  webm="https://example.org/shared/samples/quickstart.webm"
  class="foo"
>}}
{{- $sources := slice }}
{{- with .Get "mp4" }}
  {{- $sources = $sources | append . }}
{{- end }}
{{- with .Get "webm" }}
  {{- $sources = $sources | append . }}
{{- end }}

{{- with $sources -}}
  <video controls {{- with ($.Get "class") }} class="{{ . }}" {{- end }}>
    {{- range . }}
      <source src="{{ . }}" type="video/{{ path.Ext . | strings.TrimPrefix "." }}">
    {{- end }}
  </video>
{{- else }}
  {{- errorf "The %q shorcode was called without any sources. See %s" .Name .Position }}
{{- end -}}

I like this a bit better. The param names for the URLs are irrelevant, but will be sorted alphabetically to determine the order of the source elements with the video element.

{{< video
  v1="https://example.org/shared/samples/quickstart.mp4"
  v2="https://example.org/shared/samples/quickstart.webm"
  class="foo"
>}}
{{- $sources := slice }}
{{- range .Params }}
  {{- if in (slice ".mp4" ".webm" ".ogv") (path.Ext .) }}
    {{- $sources = $sources | append . }}
  {{- end }}
{{- end }}

{{- with $sources -}}
  <video controls {{- with ($.Get "class") }} class="{{ . }}" {{- end }}>
    {{- range . }}
      <source src="{{ . }}" type="video/{{ path.Ext . | strings.TrimPrefix "." }}">
    {{- end }}
  </video>
{{- else }}
  {{- warnf "The %q shorcode was called without any sources. See %s" .Name .Position }}
{{- end -}}

@jmooring
All of this works great! Much appreciated!

1 Like

Cool one! Though if I understand the spec correctly, the order should matter.

https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video#usage_notes

As you provide the url w/ the desired format and offer more widely compatible alternatives…

So in my case I want webm to render first and then the mp4 as a fall back for browsers / devices that might not be able to read the webm format…

Thanks Again!

Yeah, I edited my last response to include:

The param names for the URLs are irrelevant, but will be sorted alphabetically to determine the order of the source elements with the video element.

With this:

{{< video
  v1="https://example.org/shared/samples/quickstart.mp4"
  v2="https://example.org/shared/samples/quickstart.webm"
  class="foo"
>}}

… the mp4 will be first

With this:

{{< video
  v2="https://example.org/shared/samples/quickstart.mp4"
  v1="https://example.org/shared/samples/quickstart.webm"
  class="foo"
>}}

… the webm will be first (v1 sorts alphabetically before v2).

Within the shortcode template, .Params is a map of the parameters that you pass to it. And maps (aka dictionaries), unlike slices (aka arrays), are not ordered. But when you range (loop) through a map, the keys are ordered alphabetically.

2 Likes

Thinking this through one more time…

  • The order of source elements within the video element should be determined by the shortcode, not by the content author.
  • The media subtype and file extension may be different (e.g., ogv vs. ogg). Use a lookup table to determine media type from extension.

So…

markdown
{{< video class="foo" >}}
  https://example.org/quickstart.mp4
  https://example.org/quickstart.ogv
  https://example.org/quickstart.webm
{{< /video>}}

layouts/shortcodes/video.html
{{- /* Set order of source elements within video element. */}}
{{- $mediaTypes := slice "video/webm" "video/mp4" "video/ogg" }}

{{- /* Map media types to extensions. */}}
{{- $m := dict
  "mp4" "video/mp4"
  "webm" "video/webm"
  "ogv" "video/ogg"
}}

{{- /* Build map of sources. */}}
{{- $list := replace .Inner "\r" "\n" }}
{{- $list = split $list "\n" }}
{{- $sources := dict }}
{{- range $list }}
  {{- with (trim . " ") }}
    {{- $ext := path.Ext . | strings.TrimPrefix "." }}
    {{- $sources = merge $sources (dict (index $m $ext) .) }}
  {{- end }}
{{- end }}

{{- /* Render video element. */}}
{{- if $sources -}}
  <video controls {{- with ($.Get "class") }} class="{{ . }}" {{- end }}>
    {{- range $type := $mediaTypes }}
      {{- with index $sources . }}
        <source src="{{ . }}" type="{{ $type }}">
      {{- end }}
    {{- end }}
  </video>
{{- else }}
  {{- errorf "The %q shorcode was called without any sources. See %s" .Name .Position }}
{{- end -}}

2 Likes

This is great! More than I could have asked for. Big thanks @jmooring!

One thing I’d like to highlight, and this is a small quibble; Is that I do care about the order of the video formats, and do want them ordered w/ the webm to come first and then subsequent formats as fall-backs. Again I refer to MDN: Web video codec guide - Web media technologies | MDN

I will stress that I agree the shortcode should determine the ordering, not the content author.

Word up!

The revision above has…

That means webm first, mp4 second, ogv third.

1 Like

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