Розробка кастомного шорткоду Hugo

Наша компанія займається розробкою, підтримкою та обслуговуванням сайтів будь-якої складності. Від простих односторінкових сайтів до масштабних кластерних систем, побудованих на мікро сервісах. Досвід розробників підтверджено сертифікатами від вендорів.
Розробка та обслуговування будь-яких видів сайтів:
Інформаційні сайти або веб-програми
Сайти візитки, landing page, корпоративні сайти, онлайн каталоги, квіз, промо-сайти, блоги, ресурси новин, інформаційні портали, форуми, агрегатори
Сайти або веб-програми електронної комерції
Інтернет-магазини, B2B-портали, маркетплейси, онлайн-обмінники, кешбек-сайти, біржі, дропшиппінг-платформи, парсери товарів
Веб-програми для управління бізнес-процесами
CRM-системи, ERP-системи, корпоративні портали, системи управління виробництвом, парсери інформації
Сайти або веб-програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, конструктори сайтів, портали надання електронних послуг, відеохостинги, тематичні портали

Це лише деякі з технічних типів сайтів, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Пропоновані послуги
Показано 1 з 1 послугУсі 2065 послуг
Розробка кастомного шорткоду Hugo
Проста
~1 робочий день
Часті питання
Наші компетенції:
Етапи розробки
Останні роботи
  • image_website-b2b-advance_0.png
    Розробка сайту компанії B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    874
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Розробка веб-сайту для компанії ФІКСПЕР
    851

Розробка користувацького шорткода Hugo

Шорткоди Hugo — механізм вбудовування переиспользуемых компонентів безпосередньо в Markdown-контент. Це рішення для випадків, коли потрібно додати до статті щось складніше за звичайний текст: попередження, таблиці порівняння, вставки відео з параметрами, інтерактивні блоки. Автори контенту не торкаються HTML — вони використовують простий синтаксис.

Синтаксис виклику

{{</* callout type="warning" */>}}
Текст попередження
{{</* /callout */>}}

{{</* youtube id="dQw4w9WgXcQ" autoplay="false" */>}}

{{</* quote author="Дональд Кнут" source="Мистецтво програмування" */>}}
Передчасна оптимізація — корінь усього зла.
{{</* /quote */>}}

Два варіанти синтаксису:

  • {{< >}} — вивід без екранування HTML (для компонентів з розміткою)
  • {{% %}} — контент всередині обробляється як Markdown

Простий шорткод: callout/попередження

{{/* layouts/shortcodes/callout.html */}}
{{ $type := .Get "type" | default "info" }}
{{ $title := .Get "title" }}

{{ $icons := dict
  "info"    "ℹ️"
  "warning" "⚠️"
  "danger"  "🚨"
  "success" "✅"
  "tip"     "💡"
}}

<div class="callout callout--{{ $type }}">
  <div class="callout__icon">{{ index $icons $type }}</div>
  <div class="callout__body">
    {{ with $title }}
    <strong class="callout__title">{{ . }}</strong>
    {{ end }}
    <div class="callout__content">{{ .Inner | markdownify }}</div>
  </div>
</div>

Використання:

{{</* callout type="warning" title="Важливо" */>}}
Перед оновленням зробіть резервну копію бази даних.
{{</* /callout */>}}

Шорткод з позиційними параметрами

{{/* layouts/shortcodes/figure.html */}}
{{ $src := .Get 0 }}
{{ $alt := .Get 1 | default "" }}
{{ $caption := .Get 2 | default "" }}
{{ $width := .Get "width" | default "100%" }}

{{ $img := resources.Get $src }}
{{ if $img }}
  {{ $webp := $img | images.Resize (printf "%s WebP" (default "1200x" (.Get "resize"))) }}
  <figure class="article-figure" style="max-width: {{ $width }}">
    <picture>
      <source srcset="{{ $webp.Permalink }}" type="image/webp">
      <img src="{{ $img.Permalink }}" alt="{{ $alt }}" loading="lazy">
    </picture>
    {{ with $caption }}
    <figcaption>{{ . | markdownify }}</figcaption>
    {{ end }}
  </figure>
{{ else }}
  <!-- Fallback для зовнішніх зображень -->
  <figure class="article-figure" style="max-width: {{ $width }}">
    <img src="{{ $src }}" alt="{{ $alt }}" loading="lazy">
    {{ with $caption }}<figcaption>{{ . }}</figcaption>{{ end }}
  </figure>
{{ end }}

Використання:

{{</* figure "images/architecture.png" "Архітектура системи" "Діаграма компонентів програми" width="80%" */>}}

Шорткод з вкладками (tabs)

Складний випадок: кілька шорткодів, пов'язаних між собою через scratch:

{{/* layouts/shortcodes/tabs.html */}}
{{ .Scratch.Set "tabs" slice }}
{{ .Inner | markdownify }}

{{ $tabs := .Scratch.Get "tabs" }}
<div class="tabs" data-tabs>
  <div class="tabs__nav" role="tablist">
    {{ range $i, $tab := $tabs }}
    <button
      class="tabs__trigger{{ if eq $i 0 }} is-active{{ end }}"
      role="tab"
      aria-selected="{{ if eq $i 0 }}true{{ else }}false{{ end }}"
      aria-controls="tab-panel-{{ $tab.id }}"
    >{{ $tab.label }}</button>
    {{ end }}
  </div>
  {{ range $i, $tab := $tabs }}
  <div
    id="tab-panel-{{ $tab.id }}"
    class="tabs__panel{{ if not (eq $i 0) }} is-hidden{{ end }}"
    role="tabpanel"
  >{{ $tab.content | safeHTML }}</div>
  {{ end }}
</div>
{{/* layouts/shortcodes/tab.html */}}
{{ $label := .Get "label" }}
{{ $id := $label | urlize }}
{{ $content := .Inner | markdownify }}

{{ $tabs := .Parent.Scratch.Get "tabs" }}
{{ $tabs = $tabs | append (dict "label" $label "id" $id "content" $content) }}
{{ .Parent.Scratch.Set "tabs" $tabs }}

JavaScript для переключення:

document.querySelectorAll('[data-tabs]').forEach(tabGroup => {
  tabGroup.querySelectorAll('.tabs__trigger').forEach((trigger, i) => {
    trigger.addEventListener('click', () => {
      tabGroup.querySelectorAll('.tabs__trigger').forEach(t => {
        t.classList.remove('is-active');
        t.setAttribute('aria-selected', 'false');
      });
      tabGroup.querySelectorAll('.tabs__panel').forEach(p => p.classList.add('is-hidden'));
      trigger.classList.add('is-active');
      trigger.setAttribute('aria-selected', 'true');
      tabGroup.querySelector(`#${trigger.getAttribute('aria-controls')}`).classList.remove('is-hidden');
    });
  });
});

Шорткод для коду з заголовком

{{/* layouts/shortcodes/code.html */}}
{{ $lang := .Get "lang" | default "bash" }}
{{ $title := .Get "title" | default "" }}
{{ $filename := .Get "filename" | default "" }}

<div class="code-block">
  {{ if or $title $filename }}
  <div class="code-block__header">
    {{ with $filename }}<span class="code-block__filename">{{ . }}</span>{{ end }}
    {{ with $title }}<span class="code-block__title">{{ . }}</span>{{ end }}
    <button class="code-block__copy" onclick="copyCode(this)">Копіювати</button>
  </div>
  {{ end }}
  <div class="code-block__content">
    {{ highlight (.Inner | trim "\n") $lang "" }}
  </div>
</div>

Шорткод для таблиці порівняння

{{/* layouts/shortcodes/compare.html */}}
{{ $headers := split (.Get "headers") "," }}
{{ $rows := split .Inner "\n" | after 0 }}

<div class="compare-table-wrapper">
  <table class="compare-table">
    <thead>
      <tr>
        {{ range $headers }}
        <th>{{ . | trim " " }}</th>
        {{ end }}
      </tr>
    </thead>
    <tbody>
      {{ range $rows }}
      {{ if . }}
      <tr>
        {{ $cells := split . "|" }}
        {{ range $cells }}
        <td>{{ . | trim " " | markdownify }}</td>
        {{ end }}
      </tr>
      {{ end }}
      {{ end }}
    </tbody>
  </table>
</div>

Дебаггінг шорткодів

{{/* Вивід всіх параметрів для відладки */}}
{{ if hugo.IsServer }}
<pre class="debug-shortcode">
Params: {{ .Params | jsonify (dict "indent" "  ") }}
Inner: {{ .Inner }}
Parent: {{ with .Parent }}{{ .Name }}{{ end }}
</pre>
{{ end }}

Терміни

Один простий шорткод (попередження, цитата, badge) — 2–4 години. Набір з 5–10 шорткодів з CSS та базовим JS — 2–3 дні. Складні пов'язані шорткоди (tabs, accordion, compare table) з повним покриттям edge-кейсів — 3–5 днів.