Hugo 테마 깔끔하게 사용하기

Hugo의 테마를 "올바른 방법"으로 내 입맛에 맞게 바꿔보자 (feat. 애드센스)

Hugo? 쓸 만 해요

티스토리에서 Github Pages와 Hugo를 이용해 블로그를 운영하기 시작하기 시작한지 어언 1년이 지났다. 옮겨올 때, 예쁘면서도 난잡하지 않은 테마1를 고르는 것부터 시작해, 이 테마를 이용해 웹사이트를 빌드하고, 배포하기 위해 삽질을 했던 것을 생각하면 좀 끔찍했지만, 그래도 잘 옮겨왔다고 생각한다.

하지만, 모든 것이 일장일단이라 듯이 몇가지 불편한 점들은 있기 마련이었다. 특히, 다른 사람이 만든 것을 가져와서 쓴다는 것은, 나에게 불편한 점이 반드시 있을 거라 생각을 했고, 실제로 그러했다. 결국, 테마 Repository를 Fork해서 내 입맛에 맞게 직접 수정하게 되었다. 가령, 블로그 상단의 로고 이미지는 직접 템플릿 안의 src 값을 변경해서 적용하였고, Opengraph 태그의 화질구지한 Gravatar 프로필 이미지가 뜨는 것이 싫어 직접 변경하였다.

원조와 비교되는 것이 상당히 거슬렸다. (농담입니다)

원조와 비교되는 것이 상당히 거슬렸다. (농담입니다)

이게 최선일까…?

후자의 경우는, 내가 고쳤다면 원래 리포에 Pull Request 날려주면 좋지 않겠냐 하지만, 문제는 내가 포크한 리포에는 “내 입맛에 맞게 바꾼” ~~(사실 내 프로필 사진 링크)~~가 있었기 때문에 PR을 날리기 어려운 상태였다. 내가 정말로 PR을 날리고 싶었다면 브랜치를 새로 만들어서 보냈겠지만, 사실 귀찮았다.

나중에 확인했을 때는 원래 리포에서도 해당 버그가 해결되어 있었고, 해당 테마를 가져다2 쓰고 싶었지만 이미 원래 리포와 분기가 만들어졌기 때문에 머지를 하는 것이 꽤나 귀찮아지는 상황이 되었다. (그 때 뿐만 아니라, 그 이후도 마찬가지였을 것이다.)

특히, 이러한 불편함이 가장 크게 와닿게 된 것은 Google의 애드센스(Adsense)를 달기 시작3하면서부터 였다. 애드센스에서 자동 광고(Auto Ad)4를 제공하고 있지만, 실제 사용해보니 광고가 그닥 잘 나타나는 것 같지 않은 반면, 테마 자체는 애드센스를 고려하지 않았기 때문에 어떻게 적용해야할지 난감했다.

이러한 난감함과 함께, 몇몇 고민들이 테마 템플릿, 혹은 Hugo 자체에서 해결되지 않을까 하는 의구심에서 시작하여, 블로그 구성을 다시 하기로 하였으며, 이 글에서는 내가 고민했던 내용들을 중심으로 풀어나가보려고 한다.

(미리 스포를 하자면, 교훈은 “공식문서와 코드를 제대로 이해하자” 이다.)

시작하기 전에, 본 글은 Hugo를 이용해 Site 디렉토리를 만들고 (공식문서 링크), Git Submodule을 이용해 사이트에 테마를 적용해봤다는(공식 문서 링크) 전제 하에서 내용을 풀어나간다.

내 사진은 넣어줘야지!

Minimo 테마의 데모 페이지를 들어가보면 알 수 있듯이, 좌상단의 프로필 사진 자리에는 기본적으로 Minimo 테마의 로고가 들어가게 되어 있다. 처음 만들 때는 이걸 어떻게든 바꿔야겠다는 생각을 하고, 템플릿을 이해하지 않고 아래와 같이 img 태그의 src 속성 값에 하드 코딩하여 변경하였다. (참고로, 프로필 이미지는 Gravatar에 미리 올려둔 사진을 활용하였다.)

지금 보면 왜 이랬나 싶다.

지금 보면 왜 이랬나 싶다.

방금 전 이야기했듯이, 템플릿을 직접 수정하는 것 말고, 설정 파일을 이용해 로고의 이미지를 변경할 수 있는 방법이 있었다. 일단 테마 리포에서 로고 이미지를 렌더링하는 부분인 /layouts/partials/widgets/about.html을 확인해보자.

  
{{- $defaultConfig := .Site.Data.config.default.widgets.about -}}
{{- $configData := ( or .Site.Data.config.widgets.about $defaultConfig ) -}}
{{- $lang := .Site.Language.Lang -}}
{{- $config := ( ( index $configData $lang ) | default $configData ) -}}

<section class='widget widget-about sep-after'>
  <header>
    {{ with $config.logo }}
    <div class='logo'>
      <a href='{{ $.Site.Home.RelPermalink }}'>
        <img src='{{ . | relURL }}'>
      </a>
    </div>
    {{ end }}

img 태그의 src 속성 값으로 들어간 “.” 을 보면 아무 의미 없어보이지만, 바로 위에 with 함수가 눈에 보이게 된다. with 키워드와 end 키워드 사이에서는, $config.logo 의 값이 의문의 “.“으로 치환되어 사용되게 되는 것이다.

그렇다면 이 $config.logo 를 따라가보니, 결국엔 .Site.Data.config.widgets.about.logo 이라는 값으로 이해될 수 있다.5 이 때 나타나는 .Site.Data는 Hugo에서 **Data Template**이라는 개념으로 사용되는 것이다. 링크 걸어놓은 문서를 요약하자면, Data Template을 이용하기 위해서는

  1. 문서 프로젝트의 루트 디렉토리에 data 폴더를 만들고,
  2. 그 안에 Data Template으로 설정하고픈 값들을 알맞은 파일 형식6으로 파일을 만들어주는데,
  3. .Site.Data 바로 뒤에 오는 값은 파일명을, 그 이후부터는 해당 파일 안의 키값을 타고 들어가, 최종 값을 사용하게 되는 것이다.

즉, 테마에서 로고 사진 자리를 내가 원하는 사진 주소로 바꾸기 위해서는, .Site.Data.config.widgets.about.logo 값을 지정해주면 된다는 것이고, 이를 위해선 /data/config.toml 파일 안에 아래와 같이 정의해주면 된다는 것이다.

[widgets.about]
logo = "LINK_TO_LOGO_IMAGE"

이렇게 하면 템플릿 안에서 하드코딩할 필요가 없어진다!

애드센스를 어떻게 붙일까…

Hugo 자체적으로 구글 애널리틱스(Google Analytics)를 지원하지만, 아쉽게도 애드센스(Adsense)는 지원을 하지 않아 직접 넣어줘야한다. 사실 이 문제를 직면해서야, “테마는 테마대로 놔두고, 테마 템플릿을 덮어씌울7 수 있는 방법은 없을까” 에 대한 고민을 하게 되었다.

아니나 다를까, 역시 예상했던대로 Hugo에서 내부적으로 페이지 빌드시 참조하는 템플릿의 순서가 따로 있었다.

Hugo가 참조하는 템플릿의 순서

Hugo CLI를 이용해 Site를 만들게 되면 아래와 같은 구조를 가지게 된다.

$  tree test
test
├── archetypes
│   └── default.md
├── config.toml
├── content
├── data
├── layouts
├── static
└── themes

6 directories, 2 files

여기서 우리가 눈여겨 봐야할 디렉토리는 layoutsthemes 폴더이다. 공식 문서의 내용을 보면 알 수 있듯이, layouts 폴더 안에 해당 템플릿이 있는지 먼저 확인한 후, 없으면 지정한 테마의 폴더(themes)안 의 layouts 폴더에 정의된 템플릿을 사용한다는 것이다.

그래서 수정할 부분이 있다면, 템플릿 안의 layouts 폴더에서 해당 파일을 복사해, Site 디렉토리의 layouts 에 Path까지 그대로 가져와 넣으면 된다. 이해가 잘 안 갈 수 있을테니 단위별 광고(Ad unit) 를 넣어보면서 확인해보자.

단위별 광고를 사용한다면?

애드센스에서 단위별 광고는, 사이트 관리자가 직접 사이트의 특정 부분에 광고를 넣을 수 있도록 하는 기능이다. 편리하게도 반응형이면서, 내 광고의 크기를 CSS를 활용해 조절할 수도 있다.

본인은 이 중에서, 디스플레이 광고 를 넣을 것이고, 이를 각 블로그 글 페이지에서 커버 사진 직전과, 태그 목록 직후에 넣고 싶다. 테마에 따라 다르겠지만, Minimo 테마에서는 블로그 글을 렌더링하는 템플릿은 themes/minimo/layouts/_default/single.html 에 있었다.

{{ partial "header" . }}

<article lang='{{ .Params.lang | default .Lang }}' class='entry'>
  {{ partial "entry/header" . }}
  {{ partial "entry/cover" . }}
  {{ partial "entry/toc" . }}
  {{ partial "entry/content" . }}
  {{ partial "entry/footer" . }}
</article>
{{ partial "nav/entry_nav" . }}
{{ partial "entry/comments" . }}

{{ partial "footer" . }}

partial 은 말 그대로, 해당 페이지에 삽입할 페이지의 일부분들을 선언하는 Hugo 내장 함수이므로, 애드센스에 대한 페이지 일부를 파일로 만들어 추가해주면 되는 것이다.

그러나 위에서 얘기했듯이, 이번에는 테마 코드를 직접 수정하지 않는 것을 목표로 하고 있었기 때문에, 일단 themes/minimo/layouts/_default/single.html 파일을 layouts/_default/single.html 로 복사해왔다. 그리고 복사해온 파일에 아래와 같이 먼저 추가하였다.

{{ partial "header" . }}

<article lang='{{ .Params.lang | default .Lang }}' class='entry'>
  {{ partial "entry/header" . }}
  <!-- 애드 센스 삽입 -->
  {{ partial "widgets/adsense" .}}
  {{ partial "entry/cover" . }}
  {{ partial "entry/toc" . }}
  {{ partial "entry/content" . }}
  {{ partial "entry/footer" . }}
</article>
<!-- 애드 센스 삽입 -->
{{ partial "widgets/adsense" .}}
{{ partial "nav/entry_nav" . }}
{{ partial "entry/comments" . }}

{{ partial "footer" . }}

그러나 아직 애드센스에 대한 페이지 부분 파일이 아직 없기 때문에 layouts/widgets/adsense.html 파일을 만들어준다. 만둘어준 파일에는 애드센스에서 알려준 코드를 붙여넣기 하면 된다. (물론, 테마의 HTML 구성에 따라 필요하면 div 태그로 감싸주는 등의 수정은 좀 필요할 수 있다.)

위와 같이 해준다면, 아래와 같은 폴더/파일 구조를 가지게 되고, 로컬에서 확인을 해보면 사진과 같이 검은색으로 뜨는 것을 확인할 수 있다.

$  tree -L 3
.
├── archetypes
├── config.toml
├── content
│   └── (생략)
├── data
│   └── config.toml
├── deploy
├── layouts
│   ├── _default
│   │   └── single.html
│   └── partials
│       └── widgets
│           └── adsense.html
├── public
├── resources
├── static
└── themes
    └── minimo
        └── (생략)
localhost에서 광고를 확인하려고 할 때의 화면

localhost에서 광고를 확인하려고 할 때의 화면

이는 애드센스에 등록된 도메인이 아닌 다른 곳에서 접근이 되었기 때문이라, 실 배포를 하면 문제없이 광고가 뜰 것이다. 로컬에서는 내가 원하는 위치에 잘 들어가는지만 확인하는 정도로만 하면 된다.

자동 광고를 사용한다면?

단위별 광고 이외에, 구글이 알아서 광고를 넣을만한 위치를 찾아 넣어주는 자동 광고 기능이 있다. 자동 광고는 페이지의 <header> 부분에 사진과 같이 애드센스에서 제공하는 스크립트를 넣어주면 되어 간편하다는 장점이 있다. 이 역시 Hugo 템플릿에 삽입을 하고 싶다면 layouts 폴더에 해당 부분들을 추가해주면 된다.

참 쉽죠?

참 쉽죠?

이를 위해, 단위별 광고 를 적용할 때처럼 <header> 태그를 렌더링 하는 템플릿 파일을 복사해 와서 수정하면 되겠지만, Minimo 테마에서는 독특한 구성이 되어있는 것을 확인할 수 있었다.

<head>
  {{ partial "head/meta" . }}
  <title>{{ partial "data/title" . }}</title>
  <link rel='canonical' href='{{ .Permalink }}'>
  {{ with .OutputFormats.Get "RSS" }}
    <link href="{{ .Permalink }}" rel="alternate" type="application/rss+xml" title="{{ $.Site.Title }}" />
  {{ end }}
  {{ partial "head/hreflang" . }}
  {{ partial "head/includes" . }}
  {{ partial "head/extra" . }}
</head>

이 파일은 themes/minimo/layouts/partials/head/head.html 의 내용인데, 마지막에서 두번째 줄인 “head/extra” 가 눈에 밟혀 뭐하는 친구인가 봤더니… 내가 필요한거 넣어서 쓰란다. (링크)

그럼 그렇지!

그럼 그렇지!

그래서 애드센스에서 생성된 코드를 layouts/partials/head/extra.html 에 넣으면 만들어지는 모든 페이지의 태그 안에 스크립트가 들어가게 된다.

답은 코드 안에 있다

이렇게 해서, 목표했던대로 테마를 직접 건드리지 않고, 로고 사진 주소 수정과 ‘애드센스 붙이기’를 할 수 있었다. 아마 Hugo를 이용해 사이트를 관리하시는 분들은 많지 않겠지만, 많이들 사용하실 제킬(Jekyll)이나 다른 Site Generator들도 여기서 언급한 기능들을 활용할 수 있지 않을까 싶다.

결론은, 조금만 시간을 가져서 코드를 잘 이해하려고 노력하고 공식문서를 뒤지다보면, 내가 원하는 것을 나중에 후회할 정도로 더럽게 수정하지 않아도 된다는 것이다. 아주 기본 중의 기본이지만, 마음만 급하다보면 잊기 쉬운 내용들일 것이고, 애드센스를 사이트에 추가하는 것은 블로그를 운영하시는 분들이라면 누구나 고려하실만한 것들이라 저처럼 삽질하지 마시라고 글로 남겨본다.

P.S. 나중에 시간되면, 애드센스에 대해 별거 아니지만 삽질 줄여줄 보너스 팁들을 추가해보겠다.


  1. 많고 많은 테마를 고르다가, 컨텐츠 자체에 집중할 수 있는 Minimo 테마를 선택했다. ↩︎

  2. Hugo를 적용할 때 권장사항으로, 테마를 사용할 때는 Git Submodule를 사용하라고 한다. 자세한 내용은 여기에서 ↩︎

  3. 애드센스를 왜 이제야 달았냐고 하면, 애드센스 등록 당시에는 블로그 주소가 www.lkaybob.pe.kr 과 같이 됐어야하는데, 서브 도메인으로 설정되어 있어 등록을 하지 못했다. 하지만 최근 Netlify로 이전하며 두 주소를 모두 설정할 수 있게 되어 애드센스 활성화를 이제서야 성공할 수 있었다. ↩︎

  4. 사이트의 구성을 읽어내 알맞은 위치에 알아서 광고를 넣어주는 기능 ↩︎

  5. $config.Site.Data.config.widgets.about 까지니까. ↩︎

  6. YAML, TOML, JSON ↩︎

  7. 영어로 표현하자면, Override ↩︎