워드프레스 웹사이트를 만든다는 것은 마치 건물을 짓는 것과 같다. 여기서 ‘워드프레스 코어’는 건물의 뼈대와 기반 시설이고, ‘콘텐츠(글, 이미지 등)’는 건물 안에 채워넣을 가구와 집기들이라고 할 수 있다.
그렇다면 ‘테마’는 무엇일까? 바로 이 건물의 ‘외관 디자인’과 ‘내부 구조 설계’를 담당하는 부분이다.
워드프레스의 테마는 글, 이미지, 동영상 등 웹사이트의 콘텐츠를 방문자에게 어떤 형태로 보여줄 것인가에 대한 모든 시각적이고 구조적인 약속이라고 보면 된다.
단순히 예쁜 디자인만 의미하는 것이 아니라, 웹사이트의 레이아웃, 색상, 글꼴, 메뉴의 위치, 사이드바의 형태 등 사용자가 웹사이트를 탐색하고 콘텐츠를 소비하는 방식을 결정짓는 핵심 요소이다. 테마를 바꾸는 것만으로도 웹사이트의 느낌과 사용성이 완전히 달라진다.
페이지와 글(포스트), 왜 다르게 봐야 할까?
테마를 이해할 때 혼동하기 쉬운 개념이 바로 ‘페이지(Page)’와 ‘글(Post)’이다. 테마는 이 둘을 전혀 다른 방식으로 다루도록 설계되어 있다.
- 페이지(Page): 페이지는 정적이고 고정된 콘텐츠를 담는 데 사용된다. 시간이 지나도 내용이 크게 변하지 않는 정보, 예를 들어 ‘회사 소개’, ‘서비스 안내’, ‘오시는 길’, ‘개인정보처리방침’ 등이 페이지에 해당한다. 페이지는 보통 웹사이트의 주요 메뉴에 직접 연결되며, 시간 순서보다는 논리적인 계층 구조(예: 회사 소개 아래 ‘팀 소개’ 페이지)를 가질 수 있다. 페이지는 블로그 글처럼 목록 형태로 쭉 나열되지 않는다.
- 글(Post): 글(또는 포스트)은 시간의 흐름에 따라 축적되는 콘텐츠를 담는 데 사용된다. 블로그 게시물, 뉴스 기사, 공지사항, 업데이트 소식 등이 글에 해당한다. 글은 작성된 시간 순서대로 정렬되어 ‘블로그 목록’ 형태로 보여지는 것이 일반적이다. 또한, 카테고리나 태그를 이용하여 콘텐츠를 분류하고 관련 글들을 묶어 보여주는 기능이 강력하다.
많은 초심자가 이 둘을 구분하지 않고 ‘페이지’로 블로그 글처럼 새로운 콘텐츠를 계속 작성하는 경우가 있다.
이렇게 하면 나중에 글이 많아졌을 때 시간 순서대로 관리하거나 특정 주제별로 묶어서 보여주기가 매우 어려워진다.
또한, 워드프레스 ‘글’이 제공하는 강력한 아카이브(목록) 및 분류 기능을 전혀 활용할 수 없게 된다. 따라서 고정적인 정보는 페이지로, 시간 순서대로 쌓이는 정보는 글(포스트)로 작성하는 것을 지양해야 하겠다.
테마 파일
워드프레스 테마는 기본적으로 여러 개의 PHP, CSS, JavaScript 파일 등으로 구성된다.
파일들은 워드프레스 코어와 상호작용하며 최종적으로 사용자가 보는 웹페이지를 만들어낸다.
- style.css: 이 파일은 모든 워드프레스 테마에 반드시 있어야 하는 파일이다. 파일의 가장 윗부분에 테마의 이름, 버전, 제작자, 설명 등 테마 자체의 정보가 주석 형태로 정의되어 있다.
- index.php: 이 파일은 테마의 가장 기본이 되는 템플릿 파일이다. 워드프레스가 특정 페이지나 글을 표시하기 위해 single.php나 page.php 같은 더 구체적인 템플릿 파일을 찾지 못할 경우 최종적으로 이 파일을 사용한다.
웹사이트 설정에 따라 이 파일이 사이트의 첫 화면(홈페이지)이나 블로그 글 목록을 보여주는 데 사용될 수도 있다. 테마의 ‘기본값’ 또는 ‘후순위 템플릿’ 역할을 한다. - single.php: 이 파일은 하나의 ‘글(포스트)’을 클릭했을 때 보여지는 상세 페이지를 담당한다. 블로그 글의 제목, 내용, 작성일, 작성자 정보, 카테고리/태그, 그리고 댓글 영역 등을 어떻게 배치하고 보여줄지를 이 파일에서 정의한다.
워드프레스가 개별 글을 요청받으면, 특별한 설정이 없는 한 single.php 파일을 불러와 해당 글의 내용을 채워 넣어 보여준다. - page.php: 이 파일은 하나의 ‘페이지’를 클릭했을 때 보여지는 상세 페이지를 담당한다.
single.php와 구조적으로 유사할 수 있지만, 페이지는 보통 댓글 영역이 없거나 레이아웃이 다를 수 있다. 워드프레스가 개별 페이지를 요청받으면, 특별한 설정이 없는 한 page.php 파일을 불러와 해당 페이지의 내용을 채워 넣어 보여준다. - archive.php: 이 파일은 여러 개의 ‘글(포스트)’ 목록을 보여주는 페이지를 담당한다.
특정 카테고리나 태그를 클릭했을 때, 특정 날짜에 작성된 글들을 모아서 보고 싶을 때, 또는 단순히 블로그 글 전체 목록을 시간 순서대로 보고 싶을 때 이 템플릿이 사용된다.
여러 개의 글을 반복적으로 나열하고 요약 정보를 보여주는 형태로 구성된다.
category.php, tag.php, date.php, author.php 등 더 구체적인 아카이브 템플릿 파일이 없을 경우 archive.php가 대신 사용된다. - search.php: 이 파일은 웹사이트 검색 기능을 사용했을 때 검색 결과를 보여주는 페이지를 담당한다. 사용자가 검색창에 키워드를 입력하고 엔터를 누르면, 워드프레스는 해당 키워드와 관련된 글이나 페이지를 찾아서 이 search.php 파일의 구조에 맞춰 목록 형태로 보여준다.
- header.php: 이 파일은 웹사이트의 머리글(헤더) 영역을 담당한다. 웹사이트의 제목, 로고 이미지, 상단 메뉴(내비게이션 바), 그리고 웹페이지의 <head> 태그 안에 들어가는 중요한 정보들(문서 형식 선언, 문자 인코딩, CSS 및 JavaScript 파일 연결, 메타 정보 등)이 포함된다.
이 파일은 get_header()라는 워드프레스 함수를 이용해 index.php, single.php, page.php, archive.php 등 다른 대부분의 템플릿 파일에서 불러와 사용한다. - footer.php: 이 파일은 웹사이트의 꼬리글(푸터) 영역을 담당한다. 보통 웹사이트의 저작권 정보, 하단 메뉴, 개인정보처리방침 링크, 그리고 웹페이지의 끝을 알리는 </body>와 </html> 태그 등이 포함된다.
get_footer()라는 워드프레스 함수를 이용해 대부분의 템플릿 파일에서 불러와 사용한다. 웹사이트의 하단 영역을 통일성 있게 유지하는 역할을 한다. - sidebar.php: 이 파일은 웹사이트의 사이드바 영역을 담당한다. 블로그 글이나 페이지 옆에 부가적인 정보(최신 글 목록, 인기 글, 카테고리 목록, 태그 클라우드, 배너 광고 등)를 표시하기 위한 영역이다. 이 파일은 get_sidebar() 함수를 이용해 single.php, page.php, index.php 등 사이드바를 표시하고 싶은 템플릿 파일에서 선택적으로 불러와 사용한다. 물론 사이드바가 없는 전체 너비 레이아웃의 테마나 페이지도 많다.
- functions.php: 이 파일은 테마의 추가적인 기능이나 설정을 정의하는 핵심 파일이다.
PHP 코드를 추가하여 테마에 새로운 기능을 넣거나, 워드프레스의 기본 동작을 변경하거나, 메뉴나 위젯 영역을 등록하거나, 이미지 크기를 정의하는 등 다양한 작업을 수행할 수 있다.
파일 자체는 직접 화면에 무언가를 보여주지는 않지만, 기능을 추가하는 파일이다.
사실 이 정도 파일만 구성해도 기본적인 테마는 만들 수 있다.
파일 예제 코드
실제로 파일의 내용이 어떻게 구성되어 있는지 기본적인 코드를 살펴보자
style.css
/*
Theme Name: 내 첫 워드프레스 테마 (My First WordPress Theme)
Theme URI: http://내사이트주소.com/my-first-theme/
Author: 내 이름 (Your Name)
Author URI: http://내사이트주소.com/
Description: 워드프레스 테마 구조를 이해하기 위한 아주 기본적인 테마입니다.
Version: 1.0
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: my-first-theme // 테마 번역을 위한 고유 식별자
Tags: blog, one-column, custom-colors
이 부분은 테마 정의를 위한 주석 영역입니다.
워드프레스가 테마를 인식하는 데 사용됩니다.
*/
/* 기본적인 스타일 정의 시작 */
body {
font-family: Arial, sans-serif; /* 기본 글꼴 */
line-height: 1.6; /* 줄 간격 */
margin: 0; /* 페이지 여백 제거 */
background-color: #f4f4f4; /* 배경색 */
color: #333; /* 기본 글자색 */
}
#content {
width: 80%; /* 콘텐츠 영역 너비 */
margin: 20px auto; /* 상하 20px, 좌우 가운데 정렬 */
padding: 20px; /* 안쪽 여백 */
background-color: #fff; /* 콘텐츠 배경색 */
box-shadow: 0 0 10px rgba(0,0,0,0.1); /* 그림자 효과 */
display: flex; /* flexbox 레이아웃 사용 */
flex-wrap: wrap; /* 내용이 넘칠 경우 줄 바꿈 */
}
main {
width: 70%; /* 메인 콘텐츠 영역 너비 */
padding-right: 20px; /* 메인 콘텐츠와 사이드바 사이 여백 */
box-sizing: border-box; /* padding을 너비 계산에 포함 */
}
aside {
width: 30%; /* 사이드바 영역 너비 */
padding-left: 20px; /* 메인 콘텐츠와 사이드바 사이 여백 */
box-sizing: border-box;
border-left: 1px solid #eee; /* 사이드바 왼쪽에 구분선 */
}
header, footer {
background-color: #333; /* 헤더, 푸터 배경색 */
color: #fff; /* 헤더, 푸터 글자색 */
padding: 10px 0; /* 상하 여백 */
text-align: center; /* 가운데 정렬 */
width: 100%; /* 전체 너비 */
}
nav ul {
list-style: none; /* 목록 기호 제거 */
padding: 0;
margin: 0;
}
nav ul li {
display: inline-block; /* 메뉴 항목 가로로 나열 */
margin: 0 10px; /* 메뉴 항목 간 여백 */
}
nav ul li a {
color: #fff; /* 메뉴 링크 색상 */
text-decoration: none; /* 밑줄 제거 */
}
article {
margin-bottom: 20px; /* 글/페이지 아래 여백 */
padding-bottom: 20px;
border-bottom: 1px solid #eee; /* 글/페이지 구분선 */
}
/* 더 많은 스타일 정의... */
- 상단 주석: 워드프레스가 이 파일을 테마의
style.css
로 인식하게 하는 필수 정보다. 테마 이름, 설명, 버전 등을 기재한다. - 하단 CSS 규칙: 웹사이트의 전체적인 디자인(글꼴, 색상, 레이아웃 등)을 정의하는 스타일 코드이다. 여기서는 아주 기본적인
body
,#content
,main
,aside
,header
,footer
,nav
,article
등에 대한 스타일만 포함되어 있다.
header.php
<!DOCTYPE html>
<html <?php language_attributes(); ?>> <!-- 언어 설정 -->
<head>
<meta charset="<?php bloginfo( 'charset' ); ?>"> <!-- 문자 인코딩 설정 -->
<meta name="viewport" content="width=device-width, initial-scale=1"> <!-- 반응형 웹을 위한 뷰포트 설정 -->
<link rel="profile" href="https://gmpg.org/xfn/11">
<?php wp_head(); ?> <!-- 플러그인 및 워드프레스 핵심 기능(CSS, JS 등) 로드를 위한 필수 훅 -->
</head>
<body <?php body_class(); ?>> <!-- 페이지 종류에 따른 CSS 클래스 추가 -->
<div id="page" class="site"> <!-- 전체 페이지 컨테이너 -->
<a class="skip-link screen-reader-text" href="#content"><?php esc_html_e( 'Skip to content', 'my-first-theme' ); ?></a> <!-- 접근성을 위한 스킵 링크 -->
<header id="masthead" class="site-header"> <!-- 헤더 영역 시작 -->
<div class="site-branding"> <!-- 사이트 제목/로고 영역 -->
<?php
if ( is_front_page() && is_home() ) : // 첫 페이지(홈)인 경우
?>
<h1 class="site-title"><a href="<?php echo esc_url( home_url( '/' ) ); ?>" rel="home"><?php bloginfo( 'name' ); ?></a></h1> <!-- h1 태그로 사이트 제목 표시 -->
<?php
else : // 그 외 페이지인 경우
?>
<p class="site-title"><a href="<?php echo esc_url( home_url( '/' ) ); ?>" rel="home"><?php bloginfo( 'name' ); ?></a></p> <!-- p 태그로 사이트 제목 표시 -->
<?php
endif;
$my_first_theme_description = get_bloginfo( 'description', 'display' ); // 사이트 설명 가져오기
if ( $my_first_theme_description || is_customize_preview() ) :
?>
<p class="site-description"><?php echo $my_first_theme_description; ?></p> <!-- 사이트 설명 표시 -->
<?php endif; ?>
</div><!-- .site-branding -->
<nav id="site-navigation" class="main-navigation"> <!-- 주 메뉴 영역 -->
<?php
wp_nav_menu(
array(
'theme_location' => 'menu-1', // functions.php에서 등록한 메뉴 위치 이름
'menu_id' => 'primary-menu', // 메뉴 ID
)
);
?>
</nav><!-- #site-navigation -->
</header><!-- #masthead -->
<div id="content" class="site-content"> <!-- 메인 콘텐츠 영역 시작 (sidebar.php와 함께 사용) -->
<div id="primary" class="content-area">
<main id="main" class="site-main"> <!-- 워드프레스 루프가 실행될 메인 영역 -->
<head>
영역: 문서 형식, 문자 인코딩, 뷰포트 설정 등을 포함하며, 특히<?php wp_head(); ?>
는 워드프레스 및 플러그인이 필요한 CSS, JavaScript 등을 삽입할 수 있게 해주는 필수 함수이다.<body>
영역:<?php body_class(); ?>
는 현재 페이지의 유형(글, 페이지, 아카이브 등)에 따라 적절한 CSS 클래스를 자동으로 추가하여 스타일링을 용이하게 한다.- 사이트 제목/로고:
<?php bloginfo( 'name' ); ?>
함수로 워드프레스 설정에서 입력한 사이트 제목을 가져온다.<?php home_url( '/' ); ?>
함수로 사이트의 첫 페이지 주소를 가져와 링크를 만든다. - 주 메뉴:
<?php wp_nav_menu(); ?>
함수를 이용해 워드프레스 관리자 화면에서 설정한 메뉴를 가져와 표시한다. 이때theme_location
파라미터로functions.php
에서 정의한 메뉴 위치를 지정한다. #content
,#primary
,main
컨테이너: 뒤따라올 콘텐츠를 담을 구조를 시작한다.get_sidebar()
가 사용될 경우main
옆에aside
영역이 배치될 것이다.
footer.php
</main><!-- #main -->
</div><!-- #primary -->
<?php get_sidebar(); // 사이드바를 가져오는 함수 (sidebar.php 파일 포함) ?>
</div><!-- #content -->
<footer id="colophon" class="site-footer"> <!-- 푸터 영역 시작 -->
<div class="site-info"> <!-- 푸터 정보 영역 -->
<a href="<?php echo esc_url( __( 'https://wordpress.org/', 'my-first-theme' ) ); ?>">
<?php
/* translators: %s: CMS name, linking to its website */
printf( esc_html__( 'Proudly powered by %s', 'my-first-theme' ), 'WordPress' );
?>
</a>
<span class="sep"> | </span>
<?php
/* translators: 1: Theme name, 2: Theme author. */
printf( esc_html__( 'Theme: %1$s by %2$s.', 'my-first-theme' ), '내 첫 워드프레스 테마', '<a href="#">내 이름</a>' );
?>
</div><!-- .site-info -->
</footer><!-- #colophon -->
</div><!-- #page -->
<?php wp_footer(); ?> <!-- 플러그인 및 워드프레스 핵심 기능(JS 스크립트 등) 로드를 위한 필수 훅 -->
</body>
</html> <!-- HTML 문서 끝 -->
</main>
,</div>
,</div>
태그:header.php
에서 열었던 콘텐츠 영역 관련 태그들을 닫는다.<?php get_sidebar(); ?>
:sidebar.php
파일을 현재 템플릿에 포함시킨다. 이 함수는 사이드바가 등록되어 있고 활성화되어 있을 때만 내용을 표시한다.- 푸터 정보: 사이트 관련 정보를 표시한다.
<?php wp_footer(); ?>
:wp_head()
와 마찬가지로 워드프레스 및 플러그인이</body>
태그 앞에 필요한 코드를 삽입할 수 있게 해주는 필수 함수이다. 주로 JavaScript 스크립트가 이 위치에 로드된다.</body>
,</html>
: HTML 문서의 마지막을 닫는다.
sidebar.php
<?php
/**
* The sidebar containing the main widget area
*
* @link https://developer.wordpress.org/themes/basics/template-files/#sidebar
*
* @package My_First_WordPress_Theme
*/
if ( ! is_active_sidebar( 'sidebar-1' ) ) { // functions.php에서 등록한 'sidebar-1' 위젯 영역이 활성화되지 않았다면
return; // 아무것도 표시하지 않고 종료한다.
}
?>
<aside id="secondary" class="widget-area"> <!-- 사이드바 영역 시작 -->
<?php dynamic_sidebar( 'sidebar-1' ); // 'sidebar-1' 위젯 영역에 등록된 위젯들을 표시한다. ?>
</aside><!-- #secondary -->
<?php if ( ! is_active_sidebar( 'sidebar-1' ) ) { ... } ?>
:functions.php
에서 등록한sidebar-1
이라는 이름의 위젯 영역에 사용자가 관리자 화면에서 위젯을 추가했는지 확인한다. 위젯이 하나도 없다면 사이드바 영역 자체를 표시하지 않는다.<?php dynamic_sidebar( 'sidebar-1' ); ?>
:sidebar-1
위젯 영역에 추가된 모든 위젯(최신 글, 카테고리, 검색 등)을 이곳에 출력한다.
functions.php
<?php
/**
* My First WordPress Theme functions and definitions
*
* @link https://developer.wordpress.org/themes/basics/theme-functions/
*
* @package My_First_WordPress_Theme
*/
if ( ! function_exists( 'my_first_theme_setup' ) ) : // 함수가 이미 정의되어 있는지 확인 (다른 플러그인과의 충돌 방지)
/**
* Sets up theme defaults and registers support for various WordPress features.
*
* Note that this function is hooked into the after_setup_theme hook, which
* runs before the init hook. The init hook is too late for some features, such
* as indicating support for post thumbnails.
*/
function my_first_theme_setup() {
/*
* Make theme available for translation.
* Translations can be filed in the /languages/ directory.
* If you're building a theme based on My First WordPress Theme, use a different folder name
* to avoid overwriting the parent theme's translations.
*/
load_theme_textdomain( 'my-first-theme', get_template_directory() . '/languages' ); // 테마 번역 파일 로드
// Add default posts and comments RSS feed links to head.
add_theme_support( 'automatic-feed-links' ); // 피드 링크 자동 추가
/*
* Let WordPress manage the document title.
* By adding theme support, we declare that this theme does not use a
* hard-coded <title> tag in the document head, and expect WordPress to
* provide it for us.
*/
add_theme_support( 'title-tag' ); // <title> 태그 워드프레스에서 관리
/*
* Enable support for Post Thumbnails on posts and pages.
*
* @link https://developer.wordpress.org/themes/functionality/featured-images-post-thumbnails/
*/
add_theme_support( 'post-thumbnails' ); // 글/페이지 대표 이미지(썸네일) 지원
// This theme uses wp_nav_menu() in one location.
register_nav_menus(
array(
'menu-1' => esc_html__( 'Primary', 'my-first-theme' ), // 'Primary'라는 이름의 메뉴 위치 등록
)
);
/*
* Switch default core markup for search form, comment form, and comments
* to output valid HTML5.
*/
add_theme_support(
'html5',
array(
'search-form',
'comment-form',
'comment-list',
'gallery',
'caption',
'style',
'script',
)
); // HTML5 마크업 지원
// Set up the WordPress core custom background feature.
add_theme_support( 'custom-background', apply_filters( 'my_first_theme_custom_background_args', array(
'default-color' => 'ffffff',
'default-image' => '',
) ) ); // 사용자 정의 배경 이미지/색상 지원
// Add support for core custom logo.
add_theme_support(
'custom-logo',
array(
'height' => 250,
'width' => 250,
'flex-width' => true,
'flex-height' => true,
)
); // 사용자 정의 로고 지원
}
endif;
add_action( 'after_setup_theme', 'my_first_theme_setup' ); // 'my_first_theme_setup' 함수를 'after_setup_theme' 액션 훅에 연결
/**
* Register widget area.
*
* @link https://developer.wordpress.org/themes/functionality/sidebars/#registering-a-sidebar
*/
function my_first_theme_widgets_init() {
register_sidebar(
array(
'name' => esc_html__( 'Sidebar', 'my-first-theme' ), // 위젯 영역 이름
'id' => 'sidebar-1', // 위젯 영역 고유 ID (sidebar.php에서 사용)
'description' => esc_html__( 'Add widgets here.', 'my-first-theme' ), // 위젯 영역 설명
'before_widget' => '<section id="%1$s" class="widget %2$s">', // 위젯 시작 태그
'after_widget' => '</section>', // 위젯 끝 태그
'before_title' => '<h2 class="widget-title">', // 위젯 제목 시작 태그
'after_title' => '</h2>', // 위젯 제목 끝 태그
)
);
}
add_action( 'widgets_init', 'my_first_theme_widgets_init' ); // 'my_first_theme_widgets_init' 함수를 'widgets_init' 액션 훅에 연결
/**
* Enqueue scripts and styles.
*/
function my_first_theme_scripts() {
wp_enqueue_style( 'my-first-theme-style', get_stylesheet_uri() ); // style.css 파일 로드
// 예: 추가적인 CSS 파일 로드
// wp_enqueue_style( 'my-first-theme-additional-style', get_template_directory_uri() . '/css/additional.css', array(), '1.0' );
// 예: JavaScript 파일 로드
// wp_enqueue_script( 'my-first-theme-script', get_template_directory_uri() . '/js/custom.js', array('jquery'), '1.0', true );
}
add_action( 'wp_enqueue_scripts', 'my_first_theme_scripts' ); // 'my_first_theme_scripts' 함수를 'wp_enqueue_scripts' 액션 훅에 연결
// 테마에 필요한 추가적인 함수나 설정을 여기에 추가할 수 있다.
// 예: 특정 페이지에서의 동작 변경, 커스텀 포스트 타입 등록 등
my_first_theme_setup()
함수:after_setup_theme
훅에 연결되어 테마가 로드될 때 가장 먼저 실행된다. 이 함수 안에서add_theme_support()
함수를 이용해 테마가 지원하는 기능(제목 태그 관리, 대표 이미지, 사용자 정의 로고 등)을 워드프레스에 알린다. 또한register_nav_menus()
로 메뉴 위치를 등록한다.my_first_theme_widgets_init()
함수:widgets_init
훅에 연결되어 위젯 초기화 시점에 실행된다.register_sidebar()
함수로sidebar.php
에서 사용할 위젯 영역을 등록한다.my_first_theme_scripts()
함수:wp_enqueue_scripts
훅에 연결되어 웹페이지를 로드할 때 실행된다.wp_enqueue_style()
과wp_enqueue_script()
함수를 이용해 테마에 필요한 CSS 및 JavaScript 파일을 안전하게 로드한다. 특히style.css
는get_stylesheet_uri()
함수를 이용해 로드해야 한다.- 액션 훅 (
add_action
): 특정 시점(예: 테마 설정 후, 위젯 초기화 시, 스크립트 로드 시)에 워드프레스가 미리 정해둔 기능을 실행할 때, 내가 만든 함수(my_first_theme_setup
,my_first_theme_widgets_init
,my_first_theme_scripts
)를 함께 실행하도록 연결하는 역할을 한다.
index.php
이 파일은 가장 기본적인 콘텐츠 목록 또는 단일 콘텐츠 표시를 위한 후순위 템플릿이자, 설정에 따라서는 첫 페이지나 글 목록 페이지로 사용될 수 있다.
<?php
/**
* The main template file
*
* This is the most generic template file in a WordPress theme
* and one of the two required files for a theme (the other being style.css).
* It is used to display a page when nothing more specific matches a query.
* E.g., it puts together the home page when no home.php file exists.
*
* @link https://developer.wordpress.org/themes/basics/template-hierarchy/
*
* @package My_First_WordPress_Theme
*/
get_header(); // header.php 파일을 포함한다.
?>
<?php if ( have_posts() ) : // 표시할 글(post)이나 페이지(page)가 있는지 확인 ?>
<?php
if ( is_home() && ! is_front_page() ) : // 블로그 글 목록 페이지이면서 첫 페이지는 아닌 경우 (별도 지정 시)
?>
<header>
<h1 class="page-title screen-reader-text"><?php single_post_title(); ?></h1> <!-- 페이지 제목 표시 -->
</header>
<?php
endif;
?>
<?php
/* Start the Loop */
while ( have_posts() ) : // 표시할 글/페이지가 있는 동안 루프 시작
the_post(); // 현재 루프의 글/페이지 데이터를 가져온다. (이 함수를 호출해야 the_title(), the_content() 등을 사용할 수 있다.)
/*
* Include the Post-Type-Specific template for the content.
* If you want to override this in a child theme, then include a file
* called content-___.php (where ___ is the Post Type name) and that will be used instead.
*/
get_template_part( 'template-parts/content', get_post_type() ); // 콘텐츠 표시를 위한 템플릿 파트 파일 포함
endwhile; // 루프 끝
the_posts_navigation(); // 이전/다음 페이지 링크 표시
else : // 표시할 글/페이지가 없는 경우
get_template_part( 'template-parts/content', 'none' ); // '콘텐츠 없음' 메시지를 위한 템플릿 파트 파일 포함
endif; // 조건문 끝
?>
<?php
get_footer(); // footer.php 파일을 포함한다.
<?php get_header(); ?>
,<?php get_footer(); ?>
: 헤더와 푸터 파일을 포함시켜 웹페이지의 상단과 하단 영역을 구성한다.- The Loop (루프):
<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ... endwhile; else : ... endif; ?>
워드프레스 테마의 핵심이다. 데이터베이스에서 가져온 글이나 페이지 목록을 하나씩 순회하며 표시하는 역할을 한다.have_posts()
: 표시할 글/페이지가 있는지 확인한다.the_post()
: 현재 루프의 글/페이지 데이터를 전역 변수에 로드하여the_title()
,the_content()
등의 함수가 해당 데이터에 접근할 수 있도록 준비한다. 루프가 돌 때마다 다음 글/페이지로 넘어간다.
<?php get_template_part( 'template-parts/content', get_post_type() ); ?>
: 콘텐츠 표시를 위한 부분을 별도의 파일(template-parts/content-post.php
,template-parts/content-page.php
등)로 분리하여 포함시키는 권장 방식이다. 이렇게 하면 템플릿 파일을 깔끔하게 유지할 수 있다.<?php the_posts_navigation(); ?>
: 페이지네이션(이전/다음 페이지 링크)을 표시한다. 글 목록을 여러 페이지에 걸쳐 보여줄 때 필요하다.else
:have_posts()
결과가 false일 때 실행된다. 검색 결과가 없거나 글이 하나도 없을 때 “콘텐츠 없음” 메시지 등을 표시할 때 사용한다.
single.php
<?php
/**
* The template for displaying all single posts
*
* @link https://developer.wordpress.org/themes/basics/template-hierarchy/#single-post
*
* @package My_First_WordPress_Theme
*/
get_header(); // header.php 파일을 포함한다.
?>
<?php
while ( have_posts() ) : // 현재 글(하나)이 있는지 확인하고 루프 시작 (single.php에서는 보통 글이 하나만 로드된다)
the_post(); // 현재 글 데이터를 가져온다.
get_template_part( 'template-parts/content', get_post_type() ); // 'template-parts/content-post.php' 파일을 포함한다.
the_post_navigation( // 이전 글/다음 글 링크 표시
array(
'prev_text' => '<span class="nav-subtitle">' . esc_html__( 'Previous:', 'my-first-theme' ) . '</span> <span class="nav-title">%title</span>',
'next_text' => '<span class="nav-subtitle">' . esc_html__( 'Next:', 'my-first-theme' ) . '</span> <span class="nav-title">%title</span>',
)
);
// If comments are open or there's at least one comment, load up the comment template.
if ( comments_open() || get_comments_number() ) : // 댓글이 열려 있거나 이미 댓글이 있다면
comments_template(); // comments.php 파일을 포함하여 댓글 영역을 표시한다.
endif;
endwhile; // End of the loop.
?>
<?php
get_footer(); // footer.php 파일을 포함한다.
<?php get_header(); ?>
,<?php get_footer(); ?>
: 헤더와 푸터 파일을 포함한다.- The Loop (루프):
single.php
에서는 일반적으로 하나의 글만 로드되므로while ( have_posts() )
만 사용해도 충분하다.the_post()
함수는 필수이다. <?php get_template_part( 'template-parts/content', get_post_type() ); ?>
:index.php
와 마찬가지로 콘텐츠 본문을 표시하는 부분을 별도의 파일(template-parts/content-post.php
)로 분리하여 포함한다. 이 파일 안에는the_title()
,the_content()
함수 등이 사용될 것이다.<?php the_post_navigation(); ?>
: 현재 글의 이전 글, 다음 글 링크를 표시한다.<?php comments_template(); ?>
:comments.php
파일을 포함하여 댓글 입력 폼과 기존 댓글 목록을 표시한다. 글에만 일반적으로 사용된다.
page.php
<?php
/**
* The template for displaying all pages
*
* This is the template that displays all pages by default.
* Please note that this is the WordPress construct of pages
* and that other 'pages' on your WordPress site may use a
* different template.
*
* @link https://developer.wordpress.org/themes/basics/template-hierarchy/#page
*
* @package My_First_WordPress_Theme
*/
get_header(); // header.php 파일을 포함한다.
?>
<?php
while ( have_posts() ) : // 현재 페이지(하나)가 있는지 확인하고 루프 시작 (page.php에서는 페이지가 하나만 로드된다)
the_post(); // 현재 페이지 데이터를 가져온다.
get_template_part( 'template-parts/content', 'page' ); // 'template-parts/content-page.php' 파일을 포함한다.
// If comments are open or there's at least one comment, load up the comment template.
// 페이지에서는 보통 댓글을 사용하지 않지만, 필요에 따라 추가할 수 있다.
// if ( comments_open() || get_comments_number() ) :
// comments_template();
// endif;
endwhile; // End of the loop.
?>
<?php
get_footer(); // footer.php 파일을 포함한다.
<?php get_header(); ?>
,<?php get_footer(); ?>
: 헤더와 푸터 파일을 포함한다.- The Loop (루프):
single.php
와 마찬가지로 하나의 페이지를 로드하므로while ( have_posts() )
만 사용한다.the_post()
함수는 필수이다. <?php get_template_part( 'template-parts/content', 'page' ); ?>
: 콘텐츠 본문을 표시하는 부분을 별도의 파일(template-parts/content-page.php
)로 분리하여 포함한다. 이 파일 안에는the_title()
,the_content()
함수 등이 사용될 것이다.<?php comments_template(); ?>
: 페이지에서는 댓글을 사용하지 않는 경우가 많으므로 보통 주석 처리되거나 포함되지 않는다.
archive.php
<?php
/**
* The template for displaying archive pages
*
* @link https://developer.wordpress.org/themes/basics/template-hierarchy/#category
*
* @package My_First_WordPress_Theme
*/
get_header(); // header.php 파일을 포함한다.
?>
<?php if ( have_posts() ) : // 표시할 글 목록이 있는지 확인 ?>
<header class="page-header">
<?php
the_archive_title( '<h1 class="page-title">', '</h1>' ); // 아카이브 페이지 제목 (예: 카테고리: 웹 개발)
the_archive_description( '<div class="archive-description">', '</div>' ); // 아카이브 설명 (카테고리/태그 설명 등)
?>
</header><!-- .page-header -->
<?php
/* Start the Loop */
while ( have_posts() ) : // 표시할 글 목록이 있는 동안 루프 시작
the_post(); // 현재 루프의 글 데이터를 가져온다.
/*
* Include the Post-Type-Specific template for the content.
* If you want to override this in a child theme, then include a file
* called content-___.php (where ___ is the Post Type name) and that will be used instead.
*/
get_template_part( 'template-parts/content', get_post_type() ); // 콘텐츠 표시를 위한 템플릿 파트 파일 포함 (보통 content-excerpt.php나 content.php 사용)
endwhile; // 루프 끝
the_posts_navigation(); // 이전/다음 페이지 링크 표시
else : // 표시할 글 목록이 없는 경우
get_template_part( 'template-parts/content', 'none' ); // '콘텐츠 없음' 메시지를 위한 템플릿 파트 파일 포함
endif; // 조건문 끝
?>
<?php
get_footer(); // footer.php 파일을 포함한다.
<?php get_header(); ?>
,<?php get_footer(); ?>
: 헤더와 푸터 파일을 포함한다.<?php the_archive_title(); ?>
,<?php the_archive_description(); ?>
: 현재 아카이브 페이지의 제목(예: 카테고리 이름)과 설명을 표시한다.- The Loop (루프): 여러 개의 글 목록을 표시하므로
if ( have_posts() ) : while ( have_posts() ) : the_post(); ... endwhile; else : ... endif;
전체 구조를 사용한다. <?php get_template_part( 'template-parts/content', get_post_type() ); ?>
: 각 글의 내용을 표시하는 부분을 포함한다. 아카이브 페이지에서는 보통the_content()
대신the_excerpt()
함수를 사용하여 글의 요약만 보여주는 경우가 많다.<?php the_posts_navigation(); ?>
: 페이지네이션(이전/다음 페이지 링크)을 표시한다.else
: 해당 아카이브(카테고리, 태그 등)에 속한 글이 하나도 없을 때 실행된다.
search.php
<?php
/**
* The template for displaying search results pages
*
* @link https://developer.wordpress.org/themes/basics/template-hierarchy/#search-result
*
* @package My_First_WordPress_Theme
*/
get_header(); // header.php 파일을 포함한다.
?>
<?php if ( have_posts() ) : // 검색 결과가 있는지 확인 ?>
<header class="page-header">
<h1 class="page-title">
<?php
/* translators: %s: search query. */
printf( esc_html__( 'Search Results for: %s', 'my-first-theme' ), '<span>' . get_search_query() . '</span>' ); // 검색 결과 제목 표시 (예: 검색 결과: 워드프레스)
?>
</h1>
</header><!-- .page-header -->
<?php
/* Start the Loop */
while ( have_posts() ) : // 검색 결과 목록이 있는 동안 루프 시작
the_post(); // 현재 루프의 검색 결과 항목(글 또는 페이지) 데이터를 가져온다.
/*
* Include the Post-Type-Specific template for the content.
* If you want to override this in a child theme, then include a file
* called content-___.php (where ___ is the Post Type name) and that will be used instead.
*/
get_template_part( 'template-parts/content', 'search' ); // 검색 결과 항목 표시를 위한 템플릿 파트 파일 포함 (보통 content-search.php 사용)
endwhile; // 루프 끝
the_posts_navigation(); // 이전/다음 페이지 링크 표시
else : // 검색 결과가 없는 경우
get_template_part( 'template-parts/content', 'none' ); // '콘텐츠 없음' 메시지를 위한 템플릿 파트 파일 포함 (검색 결과 없음 메시지 표시)
endif; // 조건문 끝
?>
<?php
get_footer(); // footer.php 파일을 포함한다.
<?php get_header(); ?>
,<?php get_footer(); ?>
: 헤더와 푸터 파일을 포함한다.<?php printf( ..., get_search_query() ); ?>
: 검색어와 함께 검색 결과 제목을 표시한다.get_search_query()
함수는 사용자가 입력한 검색어를 가져온다.- The Loop (루프): 여러 개의 검색 결과를 표시하므로
if ( have_posts() ) : while ( have_posts() ) : the_post(); ... endwhile; else : ... endif;
전체 구조를 사용한다. <?php get_template_part( 'template-parts/content', 'search' ); ?>
: 각 검색 결과 항목을 표시하는 부분을 포함한다. 보통the_title()
,the_permalink()
, 그리고the_excerpt()
또는the_content()
의 일부를 사용하여 결과 미리보기를 보여준다.<?php the_posts_navigation(); ?>
: 페이지네이션(이전/다음 페이지 링크)을 표시한다. 검색 결과가 여러 페이지에 걸쳐 나올 때 필요하다.else
: 검색 결과가 하나도 없을 때 실행된다.content-none.php
파일에서 “검색 결과 없음” 메시지를 표시하게 된다.
이 예제들은 워드프레스 테마의 가장 기본적인 구조와 각 파일의 핵심적인 역할을 보여주는 것이다. 실제 테마 개발 시에는 이보다 훨씬 더 많은 파일과 기능들이 추가될 수 있다.
하지만 이 기본 파일들의 역할을 이해한다면 워드프레스 테마 구조를 파악하는 데 큰 도움이 될 것이다.