워드프레스 글(Post), 글 목록(Archive) 커스터마이징 : 동적 페이지와 function.php | 블로그 구축 #05

블로그워드프레스

안녕하세요, 생산적 회계사(PROCPA) 입니다.

지난 글에서는 워드프레스의 얼굴인 ‘메인 페이지’를 정적 페이지로 직접 빌드하는 방법을 다뤘습니다.

하지만 블로그의 핵심은 결국 ‘콘텐츠’ 입니다. 방문자가 글을 읽고, 정보를 찾는 경험이 쾌적해야 합니다.
이번 글에서는 방문자가 실제로 머무르는 공간인 ‘동적 페이지(Dynamic Page)’ 즉, 글(post)게시글 목록(archive) 을 구축하는 과정, 그리고 테마의 두뇌인 functions.php 를 통해 관리자 기능을 확장하는 노하우를 공유합니다.


1. 7단계 : 동적 페이지 빌드

1.1. 동적 페이지란?

정적 페이지가 미리 작성된 HTML 파일을 그대로 보여주는 방식이라면, 동적 페이지는 사용자의 요청이 있을 때마다 서버가 데이터베이스(DB)에서 정보를 조회하여 실시간으로 페이지를 생성하는 방식입니다. 매번 새로운 페이지를 디자인할 필요 없이, 공통된 템플릿에 DB에 저장된 데이터만 불러와 갈아 끼우는 구조이기에 대량의 콘텐츠를 효율적으로 관리할 수 있습니다.

구분정적 페이지 (Static Page)동적 페이지 (Dynamic Post/Archive)
주요 목적고정된 정보 전달 (소개, 안내 등)지속적인 콘텐츠 발행 및 아카이빙
구조적 특징계층형 (Parent-Child) 상하 구조시간순 나열 및 분류(Category/Tag) 중심
주요 예시Home, About, Contact 등개별 포스트, 카테고리/태그 목록 페이지

워드프레스의 테마는 기본적으로 single.phparchive.php 같은 표준 템플릿을 통해 일관된 디자인을 제공합니다. 하지만 저는 ‘Blog’와 ‘Docs’라는 서로 다른 성격의 콘텐츠를 효과적으로 전달하기 위해, 각각의 목적에 최적화된 디자인과 레이아웃을 별도로 구축하여 사용자 경험을 차별화했습니다.

1.2. Blog

1.2.1. 글 목록(Archive)

블로그(Blog) 섹션은 별도의 아카이브 페이지를 만드는 대신, 사용자가 특정 카테고리를 클릭했을 때 해당 카테고리에 속한 글 목록이 즉시 화면에 표시되도록 직관적으로 설계했습니다.

사용자가 카테고리를 선택하면 URL 파라미터(cat_slug)를 통해 해당 카테고리의 글을 필터링하여 동적으로 화면에 출력합니다.

구현 예시: Blog 글 목록 페이지

블로그 카테고리 목록 예시 화면

1.2.2. 글(Post)

일반적인 글읽기 화면인 single.php‘가독성(Readability)’ 오직 하나에 집중했습니다.

  1. Tailwind Typography 활용: prose 클래스를 사용하여 전문가 수준의 타이포그래피(자간, 행간, 폰트 크기 등)를 즉시 적용했습니다. 다만, 워드프레스의 ‘사용자 정의하기’에서 설정한 스타일이 제대로 반영될 수 있도록 CSS 초기화(Reset) 코드를 추가하여 디자인의 유연성과 일관성을 모두 확보했습니다.

  2. 자동 목차(TOC): 긴 글을 읽을 때 필수적인 목차를 우측 사이드바에 자동으로 생성했습니다. 별도 플러그인 없이 자바스크립트가 본문의 h2, h3 태그를 읽어 리스트를 만듭니다.

// single.php : 자동 목차 생성
const headings = article.querySelectorAll('h2, h3');
headings.forEach((heading, index) => {
    // 목차 링크 생성 및 사이드바에 추가
    const link = document.createElement('a');
    link.href = `#${heading.id}`;
    // ...
});
  1. 가독성을 높이는 메타 정보: 글의 신뢰도를 높이기 위해 ‘작성일’, ‘최종 수정일’, 그리고 ‘예상 읽는 시간’을 상단에 배치했습니다. 특히 읽는 시간은 본문의 단어 수를 계산하여 자동으로 표시되도록 로직을 작성했습니다.
<!-- single.php : 메타 정보 표시 (작성일, 수정일, 읽는 시간) -->
<ul class="flex items-center gap-4 text-sm text-slate-500">
    <!-- 작성일 -->
    <li class="flex items-center gap-1.5">
        <span class="material-symbols-outlined">calendar_today</span>
        <time datetime="<?php echo get_the_date('c'); ?>"><?php echo get_the_date('Y. m. d'); ?></time>
    </li>

    <!-- 예상 읽는 시간 계산 -->
    <?php
    $content = get_post_field('post_content', $post->ID);
    $word_count = count(preg_split('/\s+/', strip_tags($content)));
    $reading_time = ceil($word_count / 200); // 200 words per minute
    ?>
    <li class="flex items-center gap-1.5">
        <span class="material-symbols-outlined">schedule</span>
        <span><?php echo $reading_time; ?> min read</span>
    </li>
</ul>
  1. 이전 글 / 다음 글 네비게이션: 방문자가 블로그에 더 오래 머물 수 있도록 하단에 인접한 글로 이동할 수 있는 버튼을 만들었습니다. 같은 카테고리 내의 글만 연결되도록 true 파라미터를 사용했습니다.
<!-- single.php : 이전 글 / 다음 글 네비게이션 -->
<div class="mt-16 pt-8 border-t grid grid-cols-1 md:grid-cols-2 gap-4">
    <?php
    $prev_post = get_previous_post(true); // true: 같은 카테고리 내에서 이동
    $next_post = get_next_post(true);

    if ($prev_post): ?>
        <a href="<?php echo get_permalink($prev_post->ID); ?>" class="group flex flex-col items-start p-4 border rounded-lg hover:shadow-sm">
            <span class="text-sm font-bold text-slate-400 uppercase mb-1">Previous</span>
            <span class="text-sm font-bold text-slate-700 group-hover:text-indigo-600">
                <?php echo esc_html($prev_post->post_title); ?>
            </span>
        </a>
    <?php endif; ?>
</div>

구현 예시: Blog 글 페이지

워드프레스 글(Post), 글 목록(Archive) 커스터마이징 : 동적 페이지와 function.php | 블로그 구축 #05

워드프레스 글(Post), 글 목록(Archive) 커스터마이징 : 동적 페이지와 function.php | 블로그 구축 #05

1.3. Docs

1.3.1. 글 목록(Archive)

‘위키(Wiki)’ 스타일의 문서 페이지를 구축할 때 흔히 Better Docs와 같은 플러그인을 사용하곤 합니다. 하지만 무료 버전의 기능 제약과 유료 버전의 높은 비용은 큰 부담이 될 수 있습니다.

저는 별도의 플러그인 없이 기본 카테고리 구조커스텀 코드만으로 이를 구현했습니다.

  1. 카테고리 기반 레이아웃 분기: ‘Docs’ 카테고리에 속한 콘텐츠는 일반 블로그와 차별화된 레이아웃으로 제공합니다. 이를 위해 category.php 파일에서 현재 페이지가 ‘Docs’ 카테고리이거나 그 하위 카테고리인 경우를 판별하여, 위키 스타일의 전용 레이아웃을 로드하도록 로직을 구성했습니다.
// category.php : Docs 계열인지 확인
$parent_slug = 'docs';
$docs_term = get_term_by('slug', $parent_slug, 'category');
$is_docs_family = false;

if ($docs_term) {
    if ($term_id == $docs_term->term_id || cat_is_ancestor_of($docs_term->term_id, $term_id)) {
        $is_docs_family = true;
    }
}
  1. 계층형 목차 네비게이터: Docs 하위 카테고리를 자동으로 인식하여 전체 문서 구조를 한눈에 파악할 수 있는 목차 기능을 구현했습니다. 하위 카테고리 아래에 관련 글(Post)들이 논리적으로 나열되도록 설계하여 사용자가 원하는 정보를 직관적으로 찾을 수 있게 했습니다.

  2. 계층형 사이드바: 특히 공을 들인 기능으로, 3단계(대분류 > 소분류 > 글) 계층 구조를 자동으로 생성하고 현재 읽고 있는 글의 위치를 자동으로 펼쳐주는 기능을 구현하여 탐색 편의성을 극대화했습니다.

<!-- category.php : 3단계 계층 구조 사이드바 생성 -->
<?php
// Level 1: 대분류 (Sections)
$sections = get_categories(array('parent' => $term_id, 'hide_empty' => false, 'orderby' => 'id', 'order' => 'ASC'));

if (!empty($sections)) {
    foreach ($sections as $section) {
        // ... (Level 1 HTML) ...

        // Level 2: 소분류 (Sub-sections)
        $sub_sections = get_categories(array('parent' => $section->term_id, 'hide_empty' => false));
        foreach ($sub_sections as $sub) {
             // ... (Level 2 HTML) ...

             // Level 3: 글 (Posts)
             $sub_posts = get_posts(array('category' => $sub->term_id, 'numberposts' => -1, 'orderby' => 'date', 'order' => 'ASC'));
             foreach ($sub_posts as $p) {
                 // ... (Level 3 - Post Link) ...
                 echo '<a href="' . get_permalink($p->ID) . '">' . esc_html($p->post_title) . '</a>';
             }
        }
    }
}
?>
  1. 실시간 사이드바 검색: 페이지 이동 없이도 문서를 빠르게 찾을 수 있는 ‘Instant Search’ 기능을 구현했습니다. 자바스크립트를 활용해 검색어가 포함된 문서를 즉시 필터링하며, 단순 제목뿐만 아니라 ‘본문에 검색어가 몇 번 등장하는지’ 뱃지(Badge)로 표시하여 정보의 연관성을 한눈에 알 수 있게 했습니다.
// category.php : 실시간 검색 및 하이라이팅
searchInput.addEventListener('input', (e) => {
    const term = e.target.value.toLowerCase().trim();
    // 미리 준비된 JSON 데이터(window.docsSearchData - 제목, 본문 포함)에서 필터링

    if (window.docsSearchData) {
        window.docsSearchData.forEach(item => {
            const titleMatch = item.title.toLowerCase().includes(term);
            // 정규식을 사용해 본문 내 키워드 등장 횟수 계산
            const regex = new RegExp(term.replace(/[.*+?^${}()|[\]\\]/g, '\\
amp;'), 'gi');
const contentMatches = (item.content.match(regex) || []).length;
// 일치하는 항목 카운트 배지 표시 로직
if (titleMatch || contentMatches > 0) {
// ... (매칭된 ID 저장) ...
}
});
}// DOM 업데이트: 일치하지 않는 항목은 숨김(display: none) 처리
});
워드프레스 글(Post), 글 목록(Archive) 커스터마이징 : 동적 페이지와 function.php | 블로그 구축 #05

1.3.2. 글(Post)

일반 블로그 글(single.php)은 집중도를 위해 사이드바를 없애고 본문에 충실한 디자인을 택했습니다. 반면, Docs 글(docs_single.php)은 정보 탐색의 연속성이 무엇보다 중요합니다.

따라서 Archive 페이지와 동일한 사이드바를 글 상세 페이지에도 그대로 적용했습니다. 덕분에 독자는 글을 읽다가도 언제든 좌측 사이드바를 통해 상위 목차나 다른 관련 문서로 빠르게 이동할 수 있습니다. 이를 위해 functions.php에서 템플릿 라우팅을 설정하여 Docs 카테고리 글은 전용 템플릿(docs_single.php)을 타도록 만들었습니다.


2. 8단계 : functions.php 빌드

2.1. functions.php의 역할

functions.php는 테마의 두뇌입니다. 이곳에 코드를 추가하면 별도의 무거운 플러그인을 설치하지 않고도 워드프레스의 기능을 제어할 수 있습니다.

2.2. 테마 커스터마이저(Customizer) 만들기

지난 글에서 소개한 홈 화면의 ‘Docs 카드’나 ‘추천 글’ 섹션을 수정할 때마다 코드를 열어서 고치는 건 너무 귀찮은 일입니다.

그래서 워드프레스 관리자 화면(외모 > 사용자 정의하기)에서 이 내용들을 직접 수정할 수 있도록 옵션 패널 을 만들었습니다. 이제 관리자 화면에서 클릭 몇 번으로 메인 페이지의 추천 글을 바꾸고, 카테고리 연결을 변경할 수 있게 되었습니다.

// functions.php : 커스터마이저 등록
function procpa_customize_register($wp_customize) {
    // 1. Home Settings 섹션 추가
    $wp_customize->add_section('procpa_home_settings', array(
        'title' => __('Home Settings', 'procpa'),
        'priority' => 30,
    ));

    // 2. 추천 게시글 선택 옵션 추가
    $wp_customize->add_setting('featured_insight_post_id', array('transport' => 'refresh'));
    $wp_customize->add_control('featured_insight_post_id', array(
        'label' => __('Featured Insight Post', 'procpa'),
        'type' => 'select',
        'choices' => $post_choices, // 모든 글 목록을 드롭다운으로 제공
    ));
    
    // ... Docs 카드, Blog 카드 설정 등 추가
}
add_action('customize_register', 'procpa_customize_register');
워드프레스 글(Post), 글 목록(Archive) 커스터마이징 : 동적 페이지와 function.php | 블로그 구축 #05

2.3. 템플릿 라우팅 (Template Routing)

앞서 말씀드린 ‘Docs’ 카테고리는 일반 글과는 완전히 다른 디자인(docs_single.php)을 사용해야 합니다. 하지만 워드프레스 기본 구조로는 “특정 카테고리의 글”만 디자인을 바꾸는 게 쉽지 않습니다.

이때 template_include 필터를 사용하면 강제로 내가 원하는 템플릿을 불러올 수 있습니다. 이것이 템플릿 라우팅 입니다.

// functions.php : Docs 카테고리 글은 전용 템플릿 강제 적용
function procpa_load_docs_template($template) {
    if (is_singular('post')) {
        // 현재 글이 'Docs' 카테고리(또는 그 하위)에 속하는지 확인
        if (is_docs_category()) { 
            // docs_single.php 파일이 있다면 그걸 로드해라!
            $new_template = locate_template(array('docs_single.php'));
            if (!empty($new_template)) {
                return $new_template;
            }
        }
    }
    return $template;
}
add_filter('template_include', 'procpa_load_docs_template');

이 코드를 넣음으로써, 일반 글은 single.php가 처리하고, Docs 관련 글은 docs_single.php가 처리하는 완벽한 이원화 시스템이 구축되었습니다.


3. 마치며

이렇게 해서 정적 페이지동적 페이지(Single, Category), 그리고 이를 뒷받침하는 시스템(functions.php) 까지 모두 완성했습니다.

다음 시간에는 플러그인을 활용한 SEO 최적화블로그 통계 관리 등, 블로그를 안정적으로 운영하기 위한 유지보수 및 관리 방법을 다루겠습니다.

블로그 운영을 고민하시는 분들께 작은 도움이 되기를 바랍니다.