워드프레스 테마 만들기 – 3

워드프레스 테마의 뼈대와 작동 방식을 이해했다면, 이제는 살을 붙이고 옷을 입힐 차례이다.

이번 3편에서는 테마를 더욱 풍성하고 유용하게 만드는 데 필요한 몇 가지 중요한 기술과 개념들을 살펴보겠다.

1. wp_enqueue_scripts

1편에서 style.css 파일의 역할에 대해 알아보았다.

실제 테마에서는 style.css 외에도 다양한 CSS 파일이나 JavaScript 파일이 필요하다. 예를 들어, 슬라이더 기능을 넣거나, 복잡한 레이아웃을 위한 추가 CSS 프레임워크를 사용하거나, 사용자 상호작용을 위한 JavaScript 코드를 넣어야 할 수 있다.

이때, HTML <head></body> 태그 바로 앞에 <link><script> 태그를 직접 작성하여 파일을 불러오는 것은 좋은 방법이 아니다.

워드프레스에는 테마나 플러그인이 필요한 스타일(CSS)과 스크립트(JavaScript) 파일을 안전하고 효율적으로 로드(Enqueue)할 수 있는 표준적인 방법이 있다.

wp_enqueue_style() 함수와 wp_enqueue_script() 함수를 사용하는 것이다.

이 함수들은 주로 functions.php 파일에서 wp_enqueue_scripts 액션 훅을 이용하여 호출한다.

예제 코드 (functions.php):

/**
 * Enqueue scripts and styles.
 */
function my_first_theme_scripts() {
    // 기본 style.css 파일 로드
    wp_enqueue_style( 'my-first-theme-style', get_stylesheet_uri() );

    // 추가적인 CSS 파일 로드 (예: bootstrap.css)
    wp_enqueue_style( 'bootstrap-style', get_template_directory_uri() . '/css/bootstrap.min.css', array(), '3.3.7' );

    // Google Fonts 로드 (CSS 파일처럼 처리)
    wp_enqueue_style( 'google-fonts', '//fonts.googleapis.com/css?family=Nanum+Gothic:400,700&display=swap', array(), null );

    // jQuery 라이브러리 로드 (워드프레스에 내장된 버전 사용)
    wp_enqueue_script( 'jquery' );

    // 추가적인 JavaScript 파일 로드 (예: custom.js)
    // 세 번째 인자 배열은 이 스크립트가 로드되기 전에 먼저 로드되어야 할 의존성 스크립트 (여기서는 jQuery)
    // 네 번째 인자는 스크립트 버전 (캐싱 문제 방지)
    // 다섯 번째 인자는 true로 설정 시 </body> 태그 앞에 로드 (false 또는 생략 시 <head> 안에 로드)
    wp_enqueue_script( 'my-first-theme-custom-script', get_template_directory_uri() . '/js/custom.js', array('jquery'), '1.0', true );

    // 댓글 스크립트 로드 (댓글 창에서 이름/이메일 자동 채우기 기능 등)
    if ( is_singular() && comments_open() && get_option( 'thread_comments' ) ) {
        wp_enqueue_script( 'comment-reply' );
    }
}
add_action( 'wp_enqueue_scripts', 'my_first_theme_scripts' ); // 웹사이트 방문자가 페이지를 볼 때 스크립트 로드
// add_action( 'admin_enqueue_scripts', 'my_first_theme_admin_scripts' ); // 관리자 페이지에서 스크립트 로드 시

wp_enqueue_style()wp_enqueue_script() 함수를 사용하면 워드프레스가 알아서 중복 로드를 방지하고, 파일 간 의존성을 관리하며, 버전 정보를 활용하여 캐싱 문제를 해결하고, 파일 로드 위치(head 또는 body 하단)를 제어하는 등 여러 이점을 얻을 수 있다.

테마에 외부 스타일이나 스크립트를 추가할 때는 반드시 이 방법을 사용하는 것이 좋다.

2. 사용자에게 설정 권한 주기

훌륭한 테마는 단순히 예쁜 디자인을 제공하는 것을 넘어, 사용자가 자신의 취향에 맞게 웹사이트를 쉽게 변경할 수 있는 기능을 제공해야 한다. 워드프레스는 이를 위해 테마 커스터마이저(Theme Customizer)라는 기능을 제공한다.

테마 커스터마이저는 관리자 화면의 ‘외모 > 사용자 정의하기’ 메뉴를 통해 접근하며, 웹사이트의 실시간 미리보기를 보면서 테마의 다양한 설정을 변경할 수 있게 해준다. 테마 개발자는 functions.php 파일에 코드를 추가하여 이 커스터마이저에 새로운 설정 항목(패널, 섹션, 설정, 컨트롤)을 등록할 수 있다.

예제 코드 (functions.php):

/**
 * Add postMessage support for site title and description for the Theme Customizer.
 *
 * @param WP_Customize_Manager $wp_customize Theme Customizer object.
 */
function my_first_theme_customize_register( $wp_customize ) {
    // 기본 제공되는 사이트 제목, 설명, 색상 등 설정 활성화 (테마가 지원한다고 functions.php setup 함수에서 이미 선언했을 수 있다.)
    $wp_customize->get_setting( 'blogname' )->transport         = 'postMessage';
    $wp_customize->get_setting( 'blogdescription' )->transport  = 'postMessage';
    // $wp_customize->get_setting( 'header_textcolor' )->transport = 'postMessage'; // 헤더 텍스트 색상 설정이 활성화 되어있다면

    // 새로운 섹션 추가: '테마 색상 설정'
    $wp_customize->add_section( 'my_first_theme_colors_section', array(
        'title'      => __( '테마 색상 설정', 'my-first-theme' ), // 섹션 제목
        'priority'   => 30, // 다른 섹션들과의 순서
        'capability' => 'edit_theme_options', // 이 섹션을 볼 수 있는 사용자 권한
    ) );

    // 새로운 설정 추가: '메인 색상'
    $wp_customize->add_setting( 'my_first_theme_main_color', array(
        'default'    => '#0073aa', // 기본값
        'type'       => 'theme_mod', // 설정 유형 (theme_mod는 테마별로 저장)
        'capability' => 'edit_theme_options',
        'transport'  => 'refresh', // 'postMessage'로 하면 실시간 미리보기 가능 (별도 JS 필요)
        'sanitize_callback' => 'sanitize_hex_color', // 입력값 검증 함수
    ) );

    // 새로운 컨트롤 추가: '메인 색상' 설정을 제어할 UI 요소 (색상 선택기)
    $wp_customize->add_control( new WP_Customize_Color_Control( $wp_customize, 'my_first_theme_main_color_control', array(
        'label'    => __( '메인 테마 색상 선택', 'my-first-theme' ), // 컨트롤 라벨
        'section'  => 'my_first_theme_colors_section', // 위에서 정의한 섹션 ID
        'settings' => 'my_first_theme_main_color', // 위에서 정의한 설정 ID
    ) ) );

    // 예: 새로운 설정 및 컨트롤 추가: '푸터 텍스트'
    $wp_customize->add_setting( 'my_first_theme_footer_text', array(
        'default'           => '© ' . date('Y') . ' 내 첫 워드프레스 테마',
        'type'              => 'theme_mod',
        'capability'        => 'edit_theme_options',
        'transport'         => 'refresh',
        'sanitize_callback' => 'sanitize_text_field', // 일반 텍스트 검증 함수
    ) );
    $wp_customize->add_control( 'my_first_theme_footer_text_control', array( // 텍스트 입력은 별도 클래스 없이 가능
        'label'    => __( '푸터 저작권 문구', 'my-first-theme' ),
        'section'  => 'my_first_theme_colors_section', // 같은 섹션에 추가 가능
        'settings' => 'my_first_theme_footer_text',
        'type'     => 'text', // 입력 필드 유형
    ) );
}
add_action( 'customize_register', 'my_first_theme_customize_register' );

// 설정된 값을 테마에서 가져와 사용하기
// 예: style.css 또는 <head> 영역에서 동적으로 색상 적용
/*
function my_first_theme_customizer_css() {
    $main_color = get_theme_mod('my_first_theme_main_color', '#0073aa'); // 설정값 가져오기 (기본값 지정)
    if ( ! empty( $main_color ) ) {
        ?>
        <style type="text/css">
            a, .site-title a { color: <?php echo esc_attr( $main_color ); ?>; }
            .site-main button, .site-main input[type="button"], .site-main input[type="reset"], .site-main input[type="submit"] { background-color: <?php echo esc_attr( $main_color ); ?>; border-color: <?php echo esc_attr( $main_color ); ?>; }
        </style>
        <?php
    }
}
add_action( 'wp_head', 'my_first_theme_customizer_css' ); // <head> 영역에 스타일 출력

// 예: footer.php에서 푸터 텍스트 가져와 표시
// <footer>... <div><?php echo esc_html( get_theme_mod( 'my_first_theme_footer_text', '기본 푸터 텍스트' ) ); ?></div> ...</footer>
*/

이렇게 커스터마이저에 등록한 설정 값은 get_theme_mod() 함수를 사용하여 테마의 어떤 템플릿 파일에서든 가져와 적용할 수 있다. 이를 통해 사용자는 코드를 전혀 몰라도 테마의 색상, 로고, 배경 이미지, 일부 텍스트 문구 등을 쉽게 변경하여 자신의 웹사이트를 꾸밀 수 있게 된다.

3. 이미지, 폰트 등

웹사이트 디자인에는 CSS, JavaScript 외에도 이미지, 아이콘, 웹 폰트 등 다양한 자원(Assets)이 사용된다. 이 자원들을 테마 폴더 내에 잘 정리해두고, 템플릿 파일이나 CSS에서 올바른 경로로 불러와 사용하는 것이 중요하다.

일반적으로 테마 폴더 안에는 css, js, images, fonts 같은 폴더를 만들어 자원들을 종류별로 분류한다. 그리고 이 자원들을 웹에서 불러올 때는 상대 경로보다는 워드프레스 함수를 사용하여 절대 경로로 가져오는 것이 안정적이다.

주로 사용되는 경로 관련 함수:

  • get_template_directory_uri(): 현재 활성화된 부모 테마의 폴더 URL을 반환한다. (예: http://localhost/wp-content/themes/my-first-theme)
  • get_stylesheet_directory_uri(): 현재 활성화된 최상위 테마 (부모 또는 차일드 테마)의 폴더 URL을 반환한다. 차일드 테마를 사용하고 있다면 차일드 테마 폴더의 URL을 반환한다.
  • get_theme_file_uri( 'path/to/file.ext' ): 워드프레스 4.7부터 도입된 함수로, 차일드 테마에 파일이 있으면 차일드 테마 경로를, 없으면 부모 테마 경로를 자동으로 찾아서 해당 파일의 URL을 반환한다. 파일 로드 시 가장 권장되는 방법이다. (예: get_theme_file_uri( 'images/logo.png' ))
  • get_theme_file_path( 'path/to/file.ext' ): 위와 유사하지만 URL 대신 서버의 파일 시스템 경로를 반환한다. (파일을 포함시킬 때 includerequire 등에서 사용될 수 있다.)

예제 코드 (템플릿 파일에서 이미지 불러오기):

<div class="site-logo">
    <a href="<?php echo esc_url( home_url( '/' ) ); ?>">
        <!-- 테마 폴더/images/logo.png 파일을 불러옴 -->
        <img src="<?php echo esc_url( get_theme_file_uri( 'images/logo.png' ) ); ?>" alt="<?php bloginfo( 'name' ); ?>">
    </a>
</div>

예제 코드 (style.css 또는 다른 CSS 파일에서 배경 이미지 불러오기):

.page-header {
    /* 테마 폴더/images/background.jpg 파일을 불러옴 */
    background-image: url('../images/background.jpg'); /* CSS 파일 기준 상대 경로 */
    /* 또는 functions.php에서 동적으로 CSS 생성하여 절대 경로 사용 */
}

CSS에서 상대 경로를 사용할 경우, style.css 파일 자체의 위치를 기준으로 경로를 지정해야 한다. 예를 들어, style.css와 같은 레벨의 images 폴더에 이미지가 있다면 url('images/background.jpg')로, style.css보다 한 단계 위 폴더의 images 폴더에 있다면 url('../images/background.jpg')로 지정한다.

CSS 파일이 css 폴더 안에 있다면 url('../images/background.jpg')처럼 상위 폴더로 이동 후 images 폴더로 들어가야 한다.

get_theme_file_uri() 함수를 사용하여 동적으로 절대 경로를 생성하여 CSS에 삽입하는 것이 더 유연한 방법이기도 하다.

4. 대표 이미지(Featured Image) 다루기

워드프레스의 대표 이미지(Featured Image)는 글이나 페이지의 특징을 가장 잘 나타내는 이미지를 설정하는 기능이다.

뉴스 기사의 썸네일 이미지나 블로그 글의 대표 사진처럼 사용된다. 1편 functions.php 예제에서 add_theme_support( 'post-thumbnails' ); 코드를 통해 이 기능을 활성화했다.

이제 이 설정된 대표 이미지를 템플릿 파일의 원하는 위치에 표시하는 방법을 알아볼 차례이다. 주로 The Loop 안에서 다음 함수들을 사용한다.

  • has_post_thumbnail(): 현재 루프의 글/페이지에 대표 이미지가 설정되어 있는지 확인한다.
  • the_post_thumbnail( $size, $attr ): 현재 루프의 글/페이지에 설정된 대표 이미지를 HTML <img> 태그로 표시한다. $size 인자로 이미지 크기(예: ‘thumbnail’, ‘medium’, ‘large’, ‘full’ 또는 사용자 정의 크기)를 지정할 수 있고, $attr 인자로 <img> 태그에 추가할 속성(클래스, alt 텍스트 등)을 지정할 수 있다.
  • get_the_post_thumbnail_url( $post, $size ): 대표 이미지의 URL만 가져온다. 배경 이미지로 사용하거나 다른 용도로 이미지 URL이 필요할 때 유용하다.

예제 코드 (The Loop 안에서 single.php 또는 content-single.php):

<?php if ( has_post_thumbnail() ) : // 대표 이미지가 설정되어 있는지 확인 ?>
    <div class="post-thumbnail">
        <?php the_post_thumbnail( 'large', array( 'class' => 'aligncenter' ) ); // 'large' 크기의 대표 이미지 표시, 클래스 추가 ?>
    </div>
<?php endif; ?>

<div class="entry-content">
    <?php the_content(); // 글 본문 내용 ?>
</div>

예제 코드 (The Loop 안에서 archive.php 또는 content-excerpt.php):

<?php if ( has_post_thumbnail() ) : // 대표 이미지가 설정되어 있는지 확인 ?>
    <div class="post-thumbnail">
        <a href="<?php the_permalink(); ?>"> <!-- 대표 이미지에 글 링크 걸기 -->
            <?php the_post_thumbnail( 'thumbnail', array( 'alt' => get_the_title() ) ); // 'thumbnail' 크기의 대표 이미지 표시, alt 텍스트 추가 ?>
        </a>
    </div>
<?php endif; ?>

<h2><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2>
<div class="entry-excerpt">
    <?php the_excerpt(); // 글 요약 표시 ?>
</div>

대표 이미지는 사용자에게 시각적인 정보를 제공하고 웹사이트의 디자인을 더욱 풍부하게 만드는 중요한 요소이다.

5. 페이지네이션

블로그 글이나 검색 결과, 아카이브 페이지 등 목록 형태의 콘텐츠가 많아지면 한 페이지에 모두 보여주기 어렵다. 이때 콘텐츠를 여러 페이지로 나누어 보여주는 기능이 필요하며, 이를 페이지네이션이라고 한다.

워드프레스는 The Loop와 함께 사용하여 페이지네이션 링크를 쉽게 생성할 수 있는 함수들을 제공한다.

  • the_posts_navigation(): 이전 페이지 링크와 다음 페이지 링크를 간단하게 표시한다. (2편 index.php, archive.php, search.php 예제에서 사용되었다.)
<?php the_posts_navigation(); ?>
  • the_posts_pagination( $args ): 숫자 형태로 페이지 링크 목록을 표시한다. 좀 더 유연하게 페이지네이션을 제어하고 디자인할 수 있다.

예제 코드 (숫자 페이지네이션):

<?php
the_posts_pagination( array(
    'prev_text'          => __( '이전', 'my-first-theme' ),
    'next_text'          => __( '다음', 'my-first-theme' ),
    'before_page_number' => '<span class="meta-nav screen-reader-text">' . __( '페이지', 'my-first-theme' ) . ' </span>',
) );
?>

이 함수들은 현재 워드프레스가 가져온 쿼리(Query) 결과의 전체 항목 수와 한 페이지당 보여줄 항목 수를 자동으로 계산하여 필요한 페이지네이션 링크를 생성해준다.

보통 index.php, archive.php, search.php 파일의 The Loop 바깥쪽 (루프 종료 후)에 추가하여 사용한다.

6. 최종 테마 파일/폴더 구조

워드프레스 테마 개발 시 일반적으로 사용되는 파일 및 폴더 구조를 이렇게 구조화하면 코드를 찾고 관리하며 다른 개발자와 협업하기가 용이해진다.

my-first-theme/       <- 테마 루트 폴더
├── style.css         <- (필수) 테마 정보 및 주 스타일 시트
├── index.php         <- (필수) 기본 템플릿 및 대체 템플릿
├── functions.php     <- 테마 기능 정의 및 설정
├── header.php        <- 헤더 영역
├── footer.php        <- 푸터 영역
├── sidebar.php       <- 사이드바 영역
├── single.php        <- 단일 글 페이지 템플릿
├── page.php          <- 단일 페이지 템플릿
├── archive.php       <- 아카이브 페이지 템플릿 (카테고리, 태그, 날짜 등)
├── search.php        <- 검색 결과 페이지 템플릿
├── 404.php           <- 404 오류 페이지 템플릿
├── comments.php      <- 댓글 영역 템플릿
├── screenshot.png    <- 테마 미리보기 이미지 (880x660px 권장)
├── languages/        <- 테마 번역 파일 (.po, .mo) 폴더
│   └── my-first-theme.pot
├── template-parts/   <- 템플릿 조각 파일 폴더
│   ├── content/      <- 콘텐츠 유형별 템플릿 파트 (content.php, content-page.php, content-post.php 등)
│   │   └── content.php
│   │   └── content-page.php
│   │   └── content-post.php
│   └── header/       <- 헤더 관련 템플릿 파트 (예: site-branding.php, site-navigation.php)
│   └── footer/       <- 푸터 관련 템플릿 파트 (예: site-info.php)
│   └── navigation/   <- 페이지네이션/탐색 관련 템플릿 파트
│       └── navigation-posts.php
├── inc/              <- 테마 설정 및 기능 관련 파일 (functions.php가 너무 길어질 경우 분리)
│   ├── customizer.php  <- 커스터마이저 설정
│   ├── template-functions.php <- 템플릿 관련 헬퍼 함수들
│   ├── enqueue-scripts.php <- 스크립트/스타일 로드 관련 함수
│   └── ...
├── css/              <- 테마에서 사용하는 CSS 파일 폴더 (style.css 외)
│   └── bootstrap.min.css
│   └── custom-styles.css
├── js/               <- 테마에서 사용하는 JavaScript 파일 폴더
│   └── custom.js
├── images/           <- 테마에서 사용하는 이미지 파일 폴더 (로고, 배경 등)
│   └── logo.png
│   └── background.jpg
└── fonts/            <- 테마에서 사용하는 웹 폰트 파일 폴더
    └── myfont.woff2

이 구조는 권장 사항이며 테마의 복잡성에 따라 달라질 수 있다.

중요한 것은 관련된 파일들을 논리적으로 묶어서 관리하는 습관을 들이는 것이다.


다음 편에서는 아마도 테마 제작 과정을 마무리하거나, 좀 더 고급 기능(예: 커스텀 헤더/배경, 포스트 포맷, 번역 지원 등)이나 워드프레스 개발 환경 설정에 대해 다룰 수 있을 것이다.