H-Style 워드프레스 테마 기획 및 파일
H 스타일 워드프레스 디자인 가이드
1. 글보기(Single Post) — 이미지 확장 레이아웃
지시 내용:
싱글 포스트 본문 영역의 콘텐츠 가로폭은 최대 720~760px 정도로 좁게 유지하되, 본문 내 이미지(
<figure>,<img>)는 콘텐츠 영역보다 좌우로 각각 80~120px씩 더 넓게 확장 배치해주세요.구체적 CSS 방향:
- 본문 컨테이너:
max-width: 720px; margin: 0 auto;- 본문 내 이미지/figure:
width: calc(100% + 200px); margin-left: -100px; margin-right: -100px;또는vw단위 활용- 반응형에서는 모바일 기기일 때 이미지가 화면 폭 100%로 자연스럽게 리사이즈
- 이미지는
border-radius: 0(모서리 둥글림 없음), 깔끔한 직사각형 유지- 이미지 아래 캡션이 있을 경우, 캡션 텍스트는 본문 폭에 맞춰 정렬
2. H2 / H3 헤딩 태그 디자인
지시 내용:
H2 태그: 상단과 하단에 1px 실선(solid) 가로줄을 넣고, 텍스트는 그 사이에 배치합니다. 매우 미니멀한 스타일입니다.
.entry-content h2 { border-top: 1px solid #333; border-bottom: 1px solid #333; padding: 20px 0; margin: 60px 0 30px 0; font-size: 22px; font-weight: 700; line-height: 1.4; letter-spacing: -0.02em; }H3 태그: H2와 조화를 이루도록 왼쪽에만 3~4px 두께의 세로 줄(border-left)을 넣는 심플한 스타일로 디자인해주세요. (H2가 위아래 가로줄이니, H3는 방향을 바꿔 좌측 세로줄로 차별화)
.entry-content h3 { border-left: 4px solid #333; padding: 4px 0 4px 16px; margin: 40px 0 20px 0; font-size: 18px; font-weight: 700; line-height: 1.4; }전체적으로 다크 컬러(#222 ~ #333) 텍스트, 배경은 화이트, 장식 요소는 최소화합니다.
3. 하단 관련글(Related Posts) — 풀 와이드 그리드
지시 내용:
싱글 포스트 하단의 관련글 영역은 화면 전체 폭(full-width)을 사용합니다. 본문의 좁은 컨테이너를 벗어나 브라우저 전체 너비로 확장됩니다.
디자인 스펙:
- 배경색: 다크(#1a1a1a ~ #222) — 본문 화이트 배경과 대비
- 섹션 제목: "연관 기사" 형태, 중앙 정렬, 흰색 텍스트, 상단에 여백 충분히
- 그리드: 4열(데스크탑), 카드 간 간격(gap) 약 20~24px
- 각 카드 구성:
- 썸네일 이미지 (16:9 비율,
object-fit: cover)- 카테고리 라벨 (작은 태그/뱃지 형태, border 스타일)
- 제목 (흰색, 2~3줄 말줄임)
- 해시태그 목록 (회색 텍스트, 작은 폰트)
- 날짜 (회색, 가장 하단)
- 반응형: 태블릿 2열 → 모바일 1열
.related-posts-section { width: 100vw; margin-left: calc(-50vw + 50%); background: #1a1a1a; padding: 60px 40px; } .related-posts-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 24px; max-width: 1280px; margin: 0 auto; }
4. 상단 헤더 & 내비게이션 — 풀스크린 히어로 + 플로팅 네비
지시 내용:
싱글 포스트 상단 히어로 영역:
- 대표 이미지(Featured Image)를 화면 전체 폭, 높이 약 70~80vh로 배경 처리
- 이미지 위에 어두운 그라데이션 오버레이 (하단에서 상단으로
rgba(0,0,0,0.5)→transparent) 적용- 오버레이 위에 카테고리 뱃지, 글 제목, 해시태그, 날짜, 작성자 등 메타정보를 흰색 텍스트로 표시
- 제목은 큰 폰트(32~40px),
font-weight: 700, 줄간격 1.3~1.4글로벌 내비게이션:
- 화면 최상단에 고정(fixed/sticky) 배치
- 배경: 투명 → 스크롤 시 다크 배경(#000 또는 #111)으로 전환 (스크롤 이벤트 또는
backdrop-filter활용)- 로고 중앙 배치, 메뉴 항목은 로고 좌우 대칭 또는 로고 아래 중앙 정렬
- 메뉴 중 현재 활성 카테고리에는 하이라이트 배경(예: 빨간 라운드 뱃지) 적용
- 우측에 검색 아이콘, 언어 전환 등 유틸 메뉴
.site-header { position: fixed; top: 0; left: 0; width: 100%; z-index: 1000; transition: background-color 0.3s ease; } .site-header.scrolled { background-color: rgba(0, 0, 0, 0.95); }
5. 메인 페이지 인트로 — 풀스크린 그리드 최신글
지시 내용:
메인 페이지 상단은 "WHAT'S NEW" 섹션으로, 풀 와이드 다크 배경 위에 최신 글을 그리드로 나열합니다.
디자인 스펙:
- 배경: 다크(#111 ~ #1a1a1a), 전체 화면 폭 사용
- 섹션 타이틀: "WHAT'S NEW" — 대형 볼드 텍스트, 중앙 정렬, 세리프 또는 산세리프 대문자
- 타이틀 하단에 카테고리 필터 탭 (All / FACT / PRESS / TECH&AI / STORY / IR 등) — 텍스트 버튼 형태, 선택 시 밑줄 또는 볼드 활성화
- 카드 그리드: 4열 × 2행 = 8개 (또는 4열 × 3행 = 12개)
- 카드 스타일은 관련글 영역과 동일 (썸네일 + 제목 + 카테고리 뱃지 + 해시태그 + 날짜)
- 카드 호버 시 이미지 살짝 확대(
transform: scale(1.05)) + 밝기 변화.main-intro { background: #111; padding: 80px 40px; min-height: 100vh; } .main-intro h2 { font-size: 48px; font-weight: 800; color: #fff; text-align: center; margin-bottom: 30px; } .category-filter { display: flex; justify-content: center; gap: 24px; margin-bottom: 40px; } .category-filter a { color: #888; text-decoration: none; font-size: 14px; } .category-filter a.active { color: #fff; border-bottom: 2px solid #fff; }
6. 메인 하단 — "더보기" 페이징
지시 내용:
메인 페이지의 최신글 목록 하단에는 기존 페이지네이션(1, 2, 3...) 대신 "기사 더 보기" (Load More) 버튼을 중앙에 배치합니다.
디자인 스펙:
- 버튼 스타일: 원형 아이콘(+) + 텍스트 조합 또는 텍스트만 심플하게
- 참고 사이트는 (+) 기사 더 보기 형태 — 플러스 아이콘을 원형 테두리 안에 넣고 옆에 텍스트
- 색상: 밝은 회색 텍스트, 호버 시 흰색으로 전환
- 클릭 시 AJAX로 다음 글 묶음을 기존 그리드 아래에 추가 로드 (페이지 이동 없음)
- 로딩 중일 때 버튼에 스피너 또는 로딩 애니메이션 표시
.load-more-btn { display: flex; align-items: center; justify-content: center; gap: 12px; margin: 60px auto; color: #888; font-size: 16px; cursor: pointer; transition: color 0.3s; background: none; border: none; } .load-more-btn:hover { color: #fff; } .load-more-btn .icon { width: 40px; height: 40px; border: 1px solid #555; border-radius: 50%; display: flex; align-items: center; justify-content: center; }워드프레스 구현 시:
WP_Query의offset/paged파라미터와wp_ajax훅을 활용하여 REST API 또는 admin-ajax.php로 추가 글을 불러오는 방식으로 구현해주세요.
종합 — AI에게 한 번에 전달할 통합 프롬프트 (요약본)
아래는 위 내용을 하나의 지시서로 압축한 버전입니다. 실제 AI 코딩 도구에 붙여넣기 용도로 활용하세요:
워드프레스 테마 커스터마이징 요청
참고 디자인: SK Hynix Newsroom (news.skhynix.co.kr) 스타일
전체 톤: 다크 모드 기반, 미니멀, 뉴스룸/매거진 스타일. 본문은 화이트 배경.
① 싱글 포스트 본문
- 콘텐츠 폭 720px, 이미지만 좌우 100px씩 확장 (약 920px)
- 이미지는 직각 모서리, 캡션은 본문 폭 기준 정렬
② 헤딩 태그
- H2: 위아래 1px 실선 border, 패딩 20px, 매우 심플
- H3: 좌측 4px 세로선(border-left), 패딩-left 16px
③ 관련글 (싱글 하단)
- Full-width 다크 배경, 4열 그리드 카드
- 카드: 썸네일 + 카테고리 뱃지 + 제목 + 해시태그 + 날짜
④ 글 상단 히어로
- Featured Image를 full-width 70~80vh 배경으로 사용
- 어두운 그라데이션 오버레이 위에 제목/메타 정보 (흰색)
- 내비게이션은 fixed, 투명 → 스크롤 시 다크 배경 전환
⑤ 메인 페이지
- 다크 배경 풀스크린, "WHAT'S NEW" 타이틀 + 카테고리 필터 탭
- 4열 그리드 최신글 카드, 호버 시 이미지 확대 효과
⑥ 더보기 버튼
- 하단 중앙 (+) 아이콘 + "기사 더 보기" 텍스트
- AJAX load more 방식, 페이지 이동 없이 추가 로드
H-Style 워드프레스 테마
파일 구조
h-style/
├── style.css
├── functions.php
├── index.php
├── front-page.php
├── single.php
├── header.php
├── footer.php
├── searchform.php
├── search.php
├── archive.php
├── 404.php
├── page.php
├── comments.php
├── sidebar.php
├── screenshot.png
├── template-parts/
│ ├── content-card.php
│ ├── content-none.php
│ └── related-posts.php
├── inc/
│ ├── customizer.php
│ ├── template-tags.php
│ └── ajax-load-more.php
├── assets/
│ ├── css/
│ │ ├── main.css
│ │ ├── single.css
│ │ ├── front-page.css
│ │ ├── header.css
│ │ ├── archive.css
│ │ └── responsive.css
│ ├── js/
│ │ ├── navigation.js
│ │ ├── load-more.js
│ │ └── hero-scroll.js
│ └── images/
│ └── default-thumbnail.jpg
1. style.css (테마 메타 + 기본 리셋)
/*
Theme Name: H-Style
Theme URI: https://example.com/h-style
Author: Your Name
Author URI: https://example.com
Description: SK Hynix Newsroom 스타일에서 영감을 받은 다크 매거진/뉴스룸 워드프레스 테마. 풀스크린 히어로, 다크 그리드 레이아웃, 미니멀 타이포그래피.
Version: 1.0.0
Requires at least: 6.0
Tested up to: 6.7
Requires PHP: 8.0
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: h-style
Tags: dark, magazine, newsroom, grid-layout, full-width, custom-header, featured-images, blog
*/
/* ========== RESET & BASE ========== */
*,
*::before,
*::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
:root {
/* Colors */
--color-bg-dark: #111111;
--color-bg-darker: #0a0a0a;
--color-bg-card: #1a1a1a;
--color-bg-light: #ffffff;
--color-text-primary: #ffffff;
--color-text-secondary: #999999;
--color-text-muted: #666666;
--color-text-dark: #222222;
--color-text-body: #444444;
--color-border-light: #333333;
--color-border-dark: #222222;
--color-accent: #e63946;
--color-accent-hover: #c1121f;
/* Typography */
--font-primary: 'Pretendard', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
--font-heading: 'Pretendard', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
--font-display: 'Playfair Display', Georgia, serif;
/* Spacing */
--content-width: 720px;
--content-wide: 920px;
--site-max-width: 1280px;
--grid-gap: 24px;
--section-padding: 80px 40px;
/* Transitions */
--transition-fast: 0.2s ease;
--transition-normal: 0.3s ease;
--transition-slow: 0.5s ease;
}
html {
font-size: 16px;
scroll-behavior: smooth;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
body {
font-family: var(--font-primary);
line-height: 1.7;
color: var(--color-text-dark);
background-color: var(--color-bg-light);
overflow-x: hidden;
}
a {
text-decoration: none;
color: inherit;
transition: color var(--transition-fast);
}
img {
max-width: 100%;
height: auto;
display: block;
}
ul, ol {
list-style: none;
}
button {
cursor: pointer;
border: none;
background: none;
font-family: inherit;
}
/* Screen Reader Text */
.screen-reader-text {
border: 0;
clip: rect(1px, 1px, 1px, 1px);
clip-path: inset(50%);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute !important;
width: 1px;
word-wrap: normal !important;
}
2. functions.php
<?php
/**
* H-Style Theme Functions
*
* @package H-Style
* @version 1.0.0
*/
if (!defined('ABSPATH')) exit;
define('HSTYLE_VERSION', '1.0.0');
define('HSTYLE_DIR', get_template_directory());
define('HSTYLE_URI', get_template_directory_uri());
/**
* Theme Setup
*/
function hstyle_setup() {
// 번역 지원
load_theme_textdomain('h-style', HSTYLE_DIR . '/languages');
// HTML5 지원
add_theme_support('html5', array(
'search-form', 'comment-form', 'comment-list', 'gallery', 'caption', 'style', 'script'
));
// 타이틀 태그
add_theme_support('title-tag');
// 썸네일 지원
add_theme_support('post-thumbnails');
// 이미지 사이즈
add_image_size('hstyle-hero', 1920, 1080, true);
add_image_size('hstyle-card', 600, 400, true);
add_image_size('hstyle-card-large', 800, 500, true);
// 메뉴 등록
register_nav_menus(array(
'primary' => __('주 내비게이션', 'h-style'),
'footer' => __('푸터 메뉴', 'h-style'),
));
// 커스텀 로고
add_theme_support('custom-logo', array(
'height' => 50,
'width' => 200,
'flex-height' => true,
'flex-width' => true,
));
// 에디터 스타일
add_theme_support('editor-styles');
add_editor_style('assets/css/editor-style.css');
// 와이드/풀 정렬
add_theme_support('align-wide');
// 반응형 임베드
add_theme_support('responsive-embeds');
}
add_action('after_setup_theme', 'hstyle_setup');
/**
* 콘텐츠 폭 설정
*/
function hstyle_content_width() {
$GLOBALS['content_width'] = apply_filters('hstyle_content_width', 720);
}
add_action('after_setup_theme', 'hstyle_content_width', 0);
/**
* 스타일 & 스크립트 등록
*/
function hstyle_scripts() {
// Google Fonts - Pretendard
wp_enqueue_style(
'pretendard-font',
'https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/static/pretendard.min.css',
array(),
null
);
// Playfair Display (디스플레이용)
wp_enqueue_style(
'google-fonts-display',
'https://fonts.googleapis.com/css2?family=Playfair+Display:wght@700;800;900&display=swap',
array(),
null
);
// 메인 스타일
wp_enqueue_style('hstyle-main', HSTYLE_URI . '/style.css', array(), HSTYLE_VERSION);
wp_enqueue_style('hstyle-header', HSTYLE_URI . '/assets/css/header.css', array('hstyle-main'), HSTYLE_VERSION);
if (is_front_page()) {
wp_enqueue_style('hstyle-front', HSTYLE_URI . '/assets/css/front-page.css', array('hstyle-main'), HSTYLE_VERSION);
}
if (is_singular()) {
wp_enqueue_style('hstyle-single', HSTYLE_URI . '/assets/css/single.css', array('hstyle-main'), HSTYLE_VERSION);
}
if (is_archive() || is_search()) {
wp_enqueue_style('hstyle-archive', HSTYLE_URI . '/assets/css/archive.css', array('hstyle-main'), HSTYLE_VERSION);
}
wp_enqueue_style('hstyle-responsive', HSTYLE_URI . '/assets/css/responsive.css', array('hstyle-main'), HSTYLE_VERSION);
// 스크립트
wp_enqueue_script('hstyle-navigation', HSTYLE_URI . '/assets/js/navigation.js', array(), HSTYLE_VERSION, true);
if (is_front_page() || is_home() || is_archive()) {
wp_enqueue_script('hstyle-load-more', HSTYLE_URI . '/assets/js/load-more.js', array('jquery'), HSTYLE_VERSION, true);
wp_localize_script('hstyle-load-more', 'hstyleAjax', array(
'ajaxurl' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('hstyle_load_more'),
'per_page' => get_option('posts_per_page'),
));
}
if (is_singular()) {
wp_enqueue_script('hstyle-hero-scroll', HSTYLE_URI . '/assets/js/hero-scroll.js', array(), HSTYLE_VERSION, true);
if (comments_open()) {
wp_enqueue_script('comment-reply');
}
}
}
add_action('wp_enqueue_scripts', 'hstyle_scripts');
/**
* 위젯 영역
*/
function hstyle_widgets_init() {
register_sidebar(array(
'name' => __('푸터 위젯 1', 'h-style'),
'id' => 'footer-1',
'before_widget' => '<div id="%1$s" class="widget %2$s">',
'after_widget' => '</div>',
'before_title' => '<h4 class="widget-title">',
'after_title' => '</h4>',
));
register_sidebar(array(
'name' => __('푸터 위젯 2', 'h-style'),
'id' => 'footer-2',
'before_widget' => '<div id="%1$s" class="widget %2$s">',
'after_widget' => '</div>',
'before_title' => '<h4 class="widget-title">',
'after_title' => '</h4>',
));
}
add_action('widgets_init', 'hstyle_widgets_init');
/**
* 발췌문 길이
*/
function hstyle_excerpt_length($length) {
return 20;
}
add_filter('excerpt_length', 'hstyle_excerpt_length');
function hstyle_excerpt_more($more) {
return '…';
}
add_filter('excerpt_more', 'hstyle_excerpt_more');
/**
* Include files
*/
require HSTYLE_DIR . '/inc/customizer.php';
require HSTYLE_DIR . '/inc/template-tags.php';
require HSTYLE_DIR . '/inc/ajax-load-more.php';
3. header.php
<?php
/**
* Header Template
*
* @package H-Style
*/
?>
<!DOCTYPE html>
<html <?php language_attributes(); ?>>
<head>
<meta charset="<?php bloginfo('charset'); ?>">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="profile" href="https://gmpg.org/xfn/11">
<?php wp_head(); ?>
</head>
<body <?php body_class(); ?>>
<?php wp_body_open(); ?>
<div id="page" class="site">
<a class="skip-link screen-reader-text" href="#content">
<?php esc_html_e('콘텐츠로 건너뛰기', 'h-style'); ?>
</a>
<!-- Fixed Navigation -->
<header id="masthead" class="site-header">
<div class="header-inner">
<!-- Logo -->
<div class="site-branding">
<?php if (has_custom_logo()) : ?>
<?php the_custom_logo(); ?>
<?php else : ?>
<a href="<?php echo esc_url(home_url('/')); ?>" class="site-title-link">
<span class="site-title"><?php bloginfo('name'); ?></span>
</a>
<?php endif; ?>
</div>
<!-- Primary Navigation -->
<nav id="site-navigation" class="main-navigation" aria-label="<?php esc_attr_e('주 메뉴', 'h-style'); ?>">
<?php
wp_nav_menu(array(
'theme_location' => 'primary',
'menu_class' => 'primary-menu',
'container' => false,
'depth' => 2,
'fallback_cb' => 'hstyle_fallback_menu',
));
?>
</nav>
<!-- Utility -->
<div class="header-utility">
<button class="search-toggle" aria-label="<?php esc_attr_e('검색', 'h-style'); ?>">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="11" cy="11" r="8"></circle>
<line x1="21" y1="21" x2="16.65" y2="16.65"></line>
</svg>
</button>
<button class="menu-toggle" aria-label="<?php esc_attr_e('메뉴', 'h-style'); ?>" aria-expanded="false">
<span class="hamburger">
<span></span>
<span></span>
<span></span>
</span>
</button>
</div>
</div>
<!-- Search Overlay -->
<div class="search-overlay" aria-hidden="true">
<div class="search-overlay-inner">
<?php get_search_form(); ?>
<button class="search-close" aria-label="<?php esc_attr_e('검색 닫기', 'h-style'); ?>">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<line x1="18" y1="6" x2="6" y2="18"></line>
<line x1="6" y1="6" x2="18" y2="18"></line>
</svg>
</button>
</div>
</div>
</header>
<div id="content" class="site-content">
4. footer.php
<?php
/**
* Footer Template
*
* @package H-Style
*/
?>
</div><!-- #content -->
<footer id="colophon" class="site-footer">
<div class="footer-inner">
<!-- Footer Top -->
<div class="footer-top">
<div class="footer-branding">
<?php if (has_custom_logo()) : ?>
<?php the_custom_logo(); ?>
<?php else : ?>
<a href="<?php echo esc_url(home_url('/')); ?>" class="footer-logo-text">
<?php bloginfo('name'); ?>
</a>
<?php endif; ?>
<p class="footer-description"><?php bloginfo('description'); ?></p>
</div>
<?php if (has_nav_menu('footer')) : ?>
<nav class="footer-navigation" aria-label="<?php esc_attr_e('푸터 메뉴', 'h-style'); ?>">
<?php
wp_nav_menu(array(
'theme_location' => 'footer',
'menu_class' => 'footer-menu',
'container' => false,
'depth' => 1,
));
?>
</nav>
<?php endif; ?>
<div class="footer-widgets">
<?php if (is_active_sidebar('footer-1')) : ?>
<div class="footer-widget-area">
<?php dynamic_sidebar('footer-1'); ?>
</div>
<?php endif; ?>
<?php if (is_active_sidebar('footer-2')) : ?>
<div class="footer-widget-area">
<?php dynamic_sidebar('footer-2'); ?>
</div>
<?php endif; ?>
</div>
</div>
<!-- Footer Bottom -->
<div class="footer-bottom">
<p class="copyright">
© <?php echo date('Y'); ?> <?php bloginfo('name'); ?>. All rights reserved.
</p>
<button class="back-to-top" aria-label="<?php esc_attr_e('맨 위로', 'h-style'); ?>">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<polyline points="18 15 12 9 6 15"></polyline>
</svg>
</button>
</div>
</div>
</footer>
</div><!-- #page -->
<?php wp_footer(); ?>
</body>
</html>
5. front-page.php (메인 페이지)
<?php
/**
* Front Page Template
* 풀스크린 다크 그리드 메인
*
* @package H-Style
*/
get_header();
// 최신 글 쿼리
$per_page = get_option('posts_per_page', 8);
$featured_query = new WP_Query(array(
'posts_per_page' => $per_page,
'post_status' => 'publish',
'ignore_sticky_posts' => true,
));
// 카테고리 목록 (필터 탭용)
$categories = get_categories(array(
'orderby' => 'count',
'order' => 'DESC',
'hide_empty' => true,
'number' => 6,
));
?>
<!-- Hero / What's New Section -->
<section class="main-hero-section">
<div class="main-hero-inner">
<!-- Section Title -->
<h2 class="main-section-title">WHAT'S NEW</h2>
<!-- Category Filter Tabs -->
<div class="category-filter" role="tablist">
<button class="filter-tab active" data-category="all" role="tab" aria-selected="true">
All
</button>
<?php foreach ($categories as $cat) : ?>
<button class="filter-tab" data-category="<?php echo esc_attr($cat->slug); ?>" role="tab" aria-selected="false">
<?php echo esc_html($cat->name); ?>
</button>
<?php endforeach; ?>
</div>
<!-- Posts Grid -->
<?php if ($featured_query->have_posts()) : ?>
<div class="posts-grid" id="main-posts-grid">
<?php while ($featured_query->have_posts()) : $featured_query->the_post(); ?>
<?php get_template_part('template-parts/content', 'card'); ?>
<?php endwhile; ?>
</div>
<!-- Load More -->
<?php if ($featured_query->max_num_pages > 1) : ?>
<div class="load-more-wrapper">
<button class="load-more-btn" data-page="1" data-max="<?php echo esc_attr($featured_query->max_num_pages); ?>">
<span class="load-more-icon">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<line x1="12" y1="5" x2="12" y2="19"></line>
<line x1="5" y1="12" x2="19" y2="12"></line>
</svg>
</span>
<span class="load-more-text"><?php esc_html_e('기사 더 보기', 'h-style'); ?></span>
</button>
</div>
<?php endif; ?>
<?php else : ?>
<?php get_template_part('template-parts/content', 'none'); ?>
<?php endif; ?>
<?php wp_reset_postdata(); ?>
</div>
</section>
<?php get_footer(); ?>
6. single.php (글 보기)
<?php
/**
* Single Post Template
* 풀스크린 히어로 + 확장 이미지 본문
*
* @package H-Style
*/
get_header();
while (have_posts()) : the_post();
$featured_img_url = get_the_post_thumbnail_url(get_the_ID(), 'hstyle-hero');
$categories = get_the_category();
$tags = get_the_tags();
?>
<!-- Hero Section -->
<article id="post-<?php the_ID(); ?>" <?php post_class('single-article'); ?>>
<header class="single-hero" <?php if ($featured_img_url) : ?>style="background-image: url('<?php echo esc_url($featured_img_url); ?>');"<?php endif; ?>>
<div class="hero-overlay"></div>
<div class="hero-content">
<?php if ($categories) : ?>
<div class="hero-category">
<?php foreach (array_slice($categories, 0, 2) as $cat) : ?>
<a href="<?php echo esc_url(get_category_link($cat->term_id)); ?>" class="category-badge">
<?php echo esc_html($cat->name); ?>
</a>
<?php endforeach; ?>
</div>
<?php endif; ?>
<h1 class="single-title"><?php the_title(); ?></h1>
<div class="hero-meta">
<?php if ($tags) : ?>
<div class="hero-tags">
<?php foreach (array_slice($tags, 0, 5) as $tag) : ?>
<a href="<?php echo esc_url(get_tag_link($tag->term_id)); ?>" class="tag-link">
#<?php echo esc_html($tag->name); ?>
</a>
<?php endforeach; ?>
</div>
<?php endif; ?>
<div class="hero-date-author">
<time datetime="<?php echo get_the_date('c'); ?>">
<?php echo get_the_date('Y-m-d'); ?>
</time>
<span class="meta-separator">|</span>
<span class="author"><?php the_author(); ?></span>
</div>
</div>
<!-- AI 요약 / 공유 버튼 영역 -->
<div class="hero-actions">
<button class="share-btn" aria-label="<?php esc_attr_e('공유하기', 'h-style'); ?>">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="18" cy="5" r="3"></circle>
<circle cx="6" cy="12" r="3"></circle>
<circle cx="18" cy="19" r="3"></circle>
<line x1="8.59" y1="13.51" x2="15.42" y2="17.49"></line>
<line x1="15.41" y1="6.51" x2="8.59" y2="10.49"></line>
</svg>
</button>
</div>
</div>
</header>
<!-- Article Content -->
<div class="single-content-wrapper">
<div class="single-content entry-content">
<?php the_content(); ?>
</div>
<!-- Post Navigation -->
<nav class="post-navigation">
<div class="nav-links">
<?php
$prev_post = get_previous_post();
$next_post = get_next_post();
?>
<?php if ($prev_post) : ?>
<a href="<?php echo get_permalink($prev_post); ?>" class="nav-previous">
<span class="nav-label"><?php esc_html_e('이전 글', 'h-style'); ?></span>
<span class="nav-title"><?php echo esc_html($prev_post->post_title); ?></span>
</a>
<?php endif; ?>
<?php if ($next_post) : ?>
<a href="<?php echo get_permalink($next_post); ?>" class="nav-next">
<span class="nav-label"><?php esc_html_e('다음 글', 'h-style'); ?></span>
<span class="nav-title"><?php echo esc_html($next_post->post_title); ?></span>
</a>
<?php endif; ?>
</div>
</nav>
<!-- Comments -->
<?php if (comments_open() || get_comments_number()) : ?>
<div class="comments-area-wrapper">
<?php comments_template(); ?>
</div>
<?php endif; ?>
</div>
<!-- Related Posts (Full Width Dark) -->
<?php get_template_part('template-parts/related', 'posts'); ?>
</article>
<?php endwhile; ?>
<?php get_footer(); ?>
7. template-parts/content-card.php
<?php
/**
* Card Template Part
* 그리드 카드 아이템
*
* @package H-Style
*/
$categories = get_the_category();
$tags = get_the_tags();
?>
<article <?php post_class('card-item'); ?> data-category="<?php echo $categories ? esc_attr($categories[0]->slug) : ''; ?>">
<a href="<?php the_permalink(); ?>" class="card-link" aria-label="<?php the_title_attribute(); ?>">
<div class="card-thumbnail">
<?php if (has_post_thumbnail()) : ?>
<?php the_post_thumbnail('hstyle-card', array('loading' => 'lazy')); ?>
<?php else : ?>
<div class="card-no-thumb">
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#555" stroke-width="1">
<rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
<circle cx="8.5" cy="8.5" r="1.5"></circle>
<polyline points="21 15 16 10 5 21"></polyline>
</svg>
</div>
<?php endif; ?>
</div>
<div class="card-body">
<?php if ($categories) : ?>
<div class="card-category">
<span class="category-badge">
<?php echo esc_html($categories[0]->name); ?>
</span>
</div>
<?php endif; ?>
<h3 class="card-title"><?php the_title(); ?></h3>
<?php if ($tags) : ?>
<div class="card-tags">
<?php foreach (array_slice($tags, 0, 4) as $tag) : ?>
<span class="card-tag">#<?php echo esc_html($tag->name); ?></span>
<?php endforeach; ?>
</div>
<?php endif; ?>
<time class="card-date" datetime="<?php echo get_the_date('c'); ?>">
<?php echo get_the_date('Y-m-d'); ?>
</time>
</div>
</a>
</article>
8. template-parts/related-posts.php
<?php
/**
* Related Posts Section
* 풀 와이드 다크 배경 관련글
*
* @package H-Style
*/
$categories = get_the_category();
if (!$categories) return;
$cat_ids = array_map(function($cat) { return $cat->term_id; }, $categories);
$related = new WP_Query(array(
'category__in' => $cat_ids,
'post__not_in' => array(get_the_ID()),
'posts_per_page' => 4,
'ignore_sticky_posts' => true,
'orderby' => 'rand',
));
if (!$related->have_posts()) return;
?>
<section class="related-posts-section">
<div class="related-posts-inner">
<h2 class="related-title"><?php esc_html_e('연관 기사', 'h-style'); ?></h2>
<div class="related-posts-grid">
<?php while ($related->have_posts()) : $related->the_post(); ?>
<?php get_template_part('template-parts/content', 'card'); ?>
<?php endwhile; ?>
</div>
</div>
<?php wp_reset_postdata(); ?>
</section>
9. template-parts/content-none.php
<?php
/**
* No Content Template Part
*
* @package H-Style
*/
?>
<div class="no-results">
<h2 class="no-results-title">
<?php esc_html_e('게시글이 없습니다', 'h-style'); ?>
</h2>
<p class="no-results-desc">
<?php esc_html_e('아직 등록된 게시글이 없습니다. 곧 새로운 콘텐츠가 업데이트됩니다.', 'h-style'); ?>
</p>
</div>
10. index.php
<?php
/**
* Main Index Template
*
* @package H-Style
*/
get_header();
?>
<section class="main-hero-section">
<div class="main-hero-inner">
<h2 class="main-section-title">
<?php
if (is_home() && !is_front_page()) {
single_post_title();
} else {
esc_html_e("WHAT'S NEW", 'h-style');
}
?>
</h2>
<?php if (have_posts()) : ?>
<div class="posts-grid" id="main-posts-grid">
<?php while (have_posts()) : the_post(); ?>
<?php get_template_part('template-parts/content', 'card'); ?>
<?php endwhile; ?>
</div>
<?php if ($wp_query->max_num_pages > 1) : ?>
<div class="load-more-wrapper">
<button class="load-more-btn" data-page="1" data-max="<?php echo esc_attr($wp_query->max_num_pages); ?>">
<span class="load-more-icon">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<line x1="12" y1="5" x2="12" y2="19"></line>
<line x1="5" y1="12" x2="19" y2="12"></line>
</svg>
</span>
<span class="load-more-text"><?php esc_html_e('기사 더 보기', 'h-style'); ?></span>
</button>
</div>
<?php endif; ?>
<?php else : ?>
<?php get_template_part('template-parts/content', 'none'); ?>
<?php endif; ?>
</div>
</section>
<?php get_footer(); ?>
11. archive.php
<?php
/**
* Archive Template
*
* @package H-Style
*/
get_header();
?>
<section class="main-hero-section">
<div class="main-hero-inner">
<header class="archive-header">
<?php the_archive_title('<h2 class="main-section-title">', '</h2>'); ?>
<?php the_archive_description('<p class="archive-description">', '</p>'); ?>
</header>
<?php if (have_posts()) : ?>
<div class="posts-grid" id="main-posts-grid">
<?php while (have_posts()) : the_post(); ?>
<?php get_template_part('template-parts/content', 'card'); ?>
<?php endwhile; ?>
</div>
<?php if ($wp_query->max_num_pages > 1) : ?>
<div class="load-more-wrapper">
<button class="load-more-btn" data-page="1" data-max="<?php echo esc_attr($wp_query->max_num_pages); ?>">
<span class="load-more-icon">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<line x1="12" y1="5" x2="12" y2="19"></line>
<line x1="5" y1="12" x2="19" y2="12"></line>
</svg>
</span>
<span class="load-more-text"><?php esc_html_e('기사 더 보기', 'h-style'); ?></span>
</button>
</div>
<?php endif; ?>
<?php else : ?>
<?php get_template_part('template-parts/content', 'none'); ?>
<?php endif; ?>
</div>
</section>
<?php get_footer(); ?>
12. page.php
<?php
/**
* Page Template
*
* @package H-Style
*/
get_header();
while (have_posts()) : the_post();
$featured_img_url = get_the_post_thumbnail_url(get_the_ID(), 'hstyle-hero');
?>
<article id="post-<?php the_ID(); ?>" <?php post_class('single-article page-article'); ?>>
<header class="single-hero" <?php if ($featured_img_url) : ?>style="background-image: url('<?php echo esc_url($featured_img_url); ?>');"<?php endif; ?>>
<div class="hero-overlay"></div>
<div class="hero-content">
<h1 class="single-title"><?php the_title(); ?></h1>
</div>
</header>
<div class="single-content-wrapper">
<div class="single-content entry-content">
<?php the_content(); ?>
</div>
</div>
</article>
<?php endwhile; ?>
<?php get_footer(); ?>
13. search.php
<?php
/**
* Search Results Template
*
* @package H-Style
*/
get_header();
?>
<section class="main-hero-section">
<div class="main-hero-inner">
<h2 class="main-section-title">
<?php printf(esc_html__('"%s" 검색 결과', 'h-style'), get_search_query()); ?>
</h2>
<?php if (have_posts()) : ?>
<div class="posts-grid" id="main-posts-grid">
<?php while (have_posts()) : the_post(); ?>
<?php get_template_part('template-parts/content', 'card'); ?>
<?php endwhile; ?>
</div>
<?php if ($wp_query->max_num_pages > 1) : ?>
<div class="load-more-wrapper">
<button class="load-more-btn" data-page="1" data-max="<?php echo esc_attr($wp_query->max_num_pages); ?>" data-search="<?php echo esc_attr(get_search_query()); ?>">
<span class="load-more-icon">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<line x1="12" y1="5" x2="12" y2="19"></line>
<line x1="5" y1="12" x2="19" y2="12"></line>
</svg>
</span>
<span class="load-more-text"><?php esc_html_e('더 보기', 'h-style'); ?></span>
</button>
</div>
<?php endif; ?>
<?php else : ?>
<div class="no-results">
<h3 class="no-results-title"><?php esc_html_e('검색 결과가 없습니다', 'h-style'); ?></h3>
<p class="no-results-desc"><?php esc_html_e('다른 검색어로 시도해보세요.', 'h-style'); ?></p>
<?php get_search_form(); ?>
</div>
<?php endif; ?>
</div>
</section>
<?php get_footer(); ?>
14. searchform.php
<?php
/**
* Search Form Template
*
* @package H-Style
*/
?>
<form role="search" method="get" class="search-form" action="<?php echo esc_url(home_url('/')); ?>">
<label class="screen-reader-text" for="search-field">
<?php esc_html_e('검색:', 'h-style'); ?>
</label>
<input type="search" id="search-field" class="search-field"
placeholder="<?php esc_attr_e('검색어를 입력하세요…', 'h-style'); ?>"
value="<?php echo get_search_query(); ?>"
name="s"
autocomplete="off" />
<button type="submit" class="search-submit" aria-label="<?php esc_attr_e('검색', 'h-style'); ?>">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="11" cy="11" r="8"></circle>
<line x1="21" y1="21" x2="16.65" y2="16.65"></line>
</svg>
</button>
</form>
15. 404.php
<?php
/**
* 404 Template
*
* @package H-Style
*/
get_header();
?>
<section class="error-404-section">
<div class="error-404-inner">
<h1 class="error-code">404</h1>
<h2 class="error-title"><?php esc_html_e('페이지를 찾을 수 없습니다', 'h-style'); ?></h2>
<p class="error-desc"><?php esc_html_e('요청하신 페이지가 존재하지 않거나 이동되었을 수 있습니다.', 'h-style'); ?></p>
<a href="<?php echo esc_url(home_url('/')); ?>" class="error-home-link">
<?php esc_html_e('홈으로 돌아가기', 'h-style'); ?>
</a>
</div>
</section>
<?php get_footer(); ?>
16. comments.php
<?php
/**
* Comments Template
*
* @package H-Style
*/
if (post_password_required()) return;
?>
<div id="comments" class="comments-area">
<?php if (have_comments()) : ?>
<h3 class="comments-title">
<?php
printf(
esc_html(_n('댓글 %d개', '댓글 %d개', get_comments_number(), 'h-style')),
get_comments_number()
);
?>
</h3>
<ol class="comment-list">
<?php
wp_list_comments(array(
'style' => 'ol',
'short_ping' => true,
'avatar_size' => 50,
));
?>
</ol>
<?php the_comments_navigation(); ?>
<?php endif; ?>
<?php
comment_form(array(
'title_reply' => __('댓글 남기기', 'h-style'),
'title_reply_to' => __('%s에게 답글', 'h-style'),
'cancel_reply_link' => __('답글 취소', 'h-style'),
'label_submit' => __('댓글 작성', 'h-style'),
'comment_notes_before' => '',
));
?>
</div>
17. sidebar.php
<?php
/**
* Sidebar (minimal - 이 테마는 사이드바 없는 풀 레이아웃)
*
* @package H-Style
*/
if (!is_active_sidebar('sidebar-1')) return;
?>
<aside id="secondary" class="widget-area" role="complementary">
<?php dynamic_sidebar('sidebar-1'); ?>
</aside>
18. assets/css/header.css
/* ========== HEADER & NAVIGATION ========== */
.site-header {
position: fixed;
top: 0;
left: 0;
width: 100%;
z-index: 9999;
background-color: transparent;
transition: background-color var(--transition-normal), box-shadow var(--transition-normal);
}
.site-header.scrolled {
background-color: rgba(0, 0, 0, 0.95);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
box-shadow: 0 1px 0 rgba(255, 255, 255, 0.05);
}
.header-inner {
display: flex;
align-items: center;
justify-content: space-between;
max-width: var(--site-max-width);
margin: 0 auto;
padding: 0 40px;
height: 70px;
}
/* Branding */
.site-branding {
flex-shrink: 0;
}
.site-title-link {
display: flex;
align-items: center;
}
.site-title {
font-size: 20px;
font-weight: 800;
color: var(--color-text-primary);
letter-spacing: 0.05em;
text-transform: uppercase;
}
.custom-logo-link img {
height: 36px;
width: auto;
}
/* Navigation */
.main-navigation {
flex: 1;
display: flex;
justify-content: center;
}
.primary-menu {
display: flex;
align-items: center;
gap: 8px;
}
.primary-menu li {
position: relative;
}
.primary-menu li a {
display: block;
padding: 8px 16px;
font-size: 14px;
font-weight: 600;
color: rgba(255, 255, 255, 0.8);
letter-spacing: 0.02em;
border-radius: 20px;
transition: all var(--transition-fast);
}
.primary-menu li a:hover,
.primary-menu li.current-menu-item > a,
.primary-menu li.current_page_item > a {
color: #fff;
background-color: var(--color-accent);
}
/* Submenu */
.primary-menu li .sub-menu {
position: absolute;
top: 100%;
left: 50%;
transform: translateX(-50%) translateY(10px);
min-width: 180px;
background: rgba(20, 20, 20, 0.98);
backdrop-filter: blur(10px);
border-radius: 8px;
padding: 8px 0;
opacity: 0;
visibility: hidden;
transition: all var(--transition-fast);
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);
}
.primary-menu li:hover > .sub-menu {
opacity: 1;
visibility: visible;
transform: translateX(-50%) translateY(0);
}
.primary-menu li .sub-menu li a {
padding: 10px 20px;
font-size: 13px;
font-weight: 500;
border-radius: 0;
color: rgba(255, 255, 255, 0.7);
}
.primary-menu li .sub-menu li a:hover {
color: #fff;
background-color: rgba(255, 255, 255, 0.08);
}
/* Utility */
.header-utility {
display: flex;
align-items: center;
gap: 12px;
flex-shrink: 0;
}
.search-toggle,
.menu-toggle {
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
color: rgba(255, 255, 255, 0.8);
border-radius: 50%;
transition: all var(--transition-fast);
}
.search-toggle:hover,
.menu-toggle:hover {
color: #fff;
background-color: rgba(255, 255, 255, 0.1);
}
/* Hamburger */
.hamburger {
display: flex;
flex-direction: column;
gap: 5px;
width: 20px;
}
.hamburger span {
display: block;
height: 2px;
background: currentColor;
border-radius: 1px;
transition: all var(--transition-fast);
}
.menu-toggle {
display: none;
}
/* Search Overlay */
.search-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.95);
z-index: 10000;
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
visibility: hidden;
transition: all var(--transition-normal);
}
.search-overlay.active {
opacity: 1;
visibility: visible;
}
.search-overlay-inner {
width: 100%;
max-width: 600px;
padding: 0 40px;
position: relative;
}
.search-overlay .search-form {
display: flex;
align-items: center;
border-bottom: 2px solid #fff;
padding-bottom: 12px;
}
.search-overlay .search-field {
flex: 1;
background: transparent;
border: none;
outline: none;
color: #fff;
font-size: 24px;
font-family: var(--font-primary);
font-weight: 300;
}
.search-overlay .search-field::placeholder {
color: rgba(255, 255, 255, 0.4);
}
.search-overlay .search-submit {
color: #fff;
background: none;
border: none;
cursor: pointer;
}
.search-close {
position: absolute;
top: -60px;
right: 40px;
color: #fff;
width: 48px;
height: 48px;
display: flex;
align-items: center;
justify-content: center;
}
19. assets/css/front-page.css
/* ========== FRONT PAGE / MAIN ========== */
.main-hero-section {
background: var(--color-bg-dark);
min-height: 100vh;
padding: 120px 40px 80px;
}
.main-hero-inner {
max-width: var(--site-max-width);
margin: 0 auto;
}
/* Section Title */
.main-section-title {
font-family: var(--font-display);
font-size: 52px;
font-weight: 800;
color: var(--color-text-primary);
text-align: center;
margin-bottom: 36px;
letter-spacing: 0.02em;
}
/* Category Filter */
.category-filter {
display: flex;
justify-content: center;
align-items: center;
gap: 28px;
margin-bottom: 50px;
flex-wrap: wrap;
}
.filter-tab {
font-size: 14px;
font-weight: 500;
color: var(--color-text-secondary);
padding: 6px 2px;
border-bottom: 2px solid transparent;
transition: all var(--transition-fast);
letter-spacing: 0.02em;
background: none;
cursor: pointer;
}
.filter-tab:hover {
color: var(--color-text-primary);
}
.filter-tab.active {
color: var(--color-text-primary);
border-bottom-color: var(--color-text-primary);
}
/* Posts Grid */
.posts-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: var(--grid-gap);
}
/* Card Item */
.card-item {
border-radius: 0;
overflow: hidden;
transition: transform var(--transition-normal);
}
.card-link {
display: block;
height: 100%;
}
.card-thumbnail {
position: relative;
padding-top: 66.67%; /* 3:2 ratio */
overflow: hidden;
background: var(--color-bg-card);
}
.card-thumbnail img {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: cover;
transition: transform var(--transition-slow), opacity var(--transition-normal);
}
.card-item:hover .card-thumbnail img {
transform: scale(1.05);
opacity: 0.85;
}
.card-no-thumb {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background: var(--color-bg-card);
}
/* Card Body */
.card-body {
padding: 20px 4px;
}
.card-category {
margin-bottom: 10px;
}
.category-badge {
display: inline-block;
font-size: 11px;
font-weight: 600;
color: var(--color-text-secondary);
border: 1px solid var(--color-border-light);
padding: 3px 10px;
border-radius: 3px;
letter-spacing: 0.03em;
text-transform: uppercase;
}
.card-title {
font-size: 16px;
font-weight: 700;
color: var(--color-text-primary);
line-height: 1.5;
margin-bottom: 12px;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
transition: color var(--transition-fast);
}
.card-item:hover .card-title {
color: rgba(255, 255, 255, 0.8);
}
.card-tags {
display: flex;
flex-wrap: wrap;
gap: 6px;
margin-bottom: 10px;
}
.card-tag {
font-size: 12px;
color: var(--color-text-muted);
font-weight: 400;
}
.card-date {
font-size: 12px;
color: var(--color-text-muted);
display: block;
}
/* Archive Description */
.archive-header {
text-align: center;
margin-bottom: 20px;
}
.archive-description {
color: var(--color-text-secondary);
font-size: 15px;
margin-top: 12px;
}
/* Load More */
.load-more-wrapper {
display: flex;
justify-content: center;
margin-top: 60px;
}
.load-more-btn {
display: flex;
align-items: center;
gap: 12px;
color: var(--color-text-secondary);
font-size: 15px;
font-weight: 500;
cursor: pointer;
transition: color var(--transition-fast);
padding: 12px 24px;
}
.load-more-btn:hover {
color: var(--color-text-primary);
}
.load-more-icon {
width: 44px;
height: 44px;
border: 1px solid var(--color-border-light);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
transition: border-color var(--transition-fast);
}
.load-more-btn:hover .load-more-icon {
border-color: var(--color-text-primary);
}
.load-more-btn.loading .load-more-icon {
animation: spin 1s linear infinite;
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
/* No Results */
.no-results {
text-align: center;
padding: 100px 20px;
}
.no-results-title {
font-size: 28px;
font-weight: 700;
color: var(--color-text-primary);
margin-bottom: 16px;
}
.no-results-desc {
font-size: 15px;
color: var(--color-text-secondary);
}
.no-results .search-form {
max-width: 400px;
margin: 30px auto 0;
display: flex;
border-bottom: 1px solid var(--color-border-light);
padding-bottom: 8px;
}
.no-results .search-field {
flex: 1;
background: transparent;
border: none;
outline: none;
color: #fff;
font-size: 16px;
font-family: var(--font-primary);
}
.no-results .search-submit {
color: var(--color-text-secondary);
}
20. assets/css/single.css
/* ========== SINGLE POST ========== */
/* Hero */
.single-hero {
position: relative;
width: 100%;
min-height: 75vh;
display: flex;
align-items: flex-end;
background-size: cover;
background-position: center;
background-repeat: no-repeat;
background-color: var(--color-bg-dark);
}
.hero-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(
to bottom,
rgba(0, 0, 0, 0.1) 0%,
rgba(0, 0, 0, 0.3) 40%,
rgba(0, 0, 0, 0.7) 80%,
rgba(0, 0, 0, 0.85) 100%
);
z-index: 1;
}
.hero-content {
position: relative;
z-index: 2;
max-width: 900px;
padding: 60px 60px 60px;
width: 100%;
}
/* Category Badge in Hero */
.hero-category {
display: flex;
gap: 8px;
margin-bottom: 20px;
}
.hero-category .category-badge {
font-size: 12px;
font-weight: 600;
color: #fff;
border: 1px solid rgba(255, 255, 255, 0.5);
padding: 5px 14px;
border-radius: 3px;
letter-spacing: 0.05em;
text-transform: uppercase;
}
.hero-category .category-badge:hover {
background: rgba(255, 255, 255, 0.15);
}
/* Title */
.single-title {
font-size: 38px;
font-weight: 800;
color: #fff;
line-height: 1.35;
letter-spacing: -0.02em;
margin-bottom: 24px;
}
/* Hero Meta */
.hero-meta {
display: flex;
flex-direction: column;
gap: 12px;
}
.hero-tags {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.tag-link {
font-size: 13px;
color: rgba(255, 255, 255, 0.6);
transition: color var(--transition-fast);
}
.tag-link:hover {
color: #fff;
}
.hero-date-author {
font-size: 14px;
color: rgba(255, 255, 255, 0.5);
display: flex;
align-items: center;
gap: 10px;
}
.meta-separator {
opacity: 0.4;
}
.hero-actions {
position: absolute;
bottom: 60px;
right: 60px;
}
.share-btn {
width: 44px;
height: 44px;
border-radius: 50%;
border: 1px solid rgba(255, 255, 255, 0.3);
color: rgba(255, 255, 255, 0.7);
display: flex;
align-items: center;
justify-content: center;
transition: all var(--transition-fast);
}
.share-btn:hover {
background: rgba(255, 255, 255, 0.1);
border-color: rgba(255, 255, 255, 0.6);
color: #fff;
}
/* Content Wrapper */
.single-content-wrapper {
max-width: var(--content-width);
margin: 0 auto;
padding: 60px 20px 80px;
}
/* Entry Content - Typography */
.entry-content {
font-size: 17px;
line-height: 1.85;
color: var(--color-text-body);
word-break: keep-all;
overflow-wrap: break-word;
}
.entry-content p {
margin-bottom: 28px;
}
.entry-content a {
color: var(--color-accent);
text-decoration: underline;
text-underline-offset: 3px;
}
.entry-content a:hover {
color: var(--color-accent-hover);
}
/* H2 - 위아래 실선 */
.entry-content h2 {
border-top: 1px solid #333;
border-bottom: 1px solid #333;
padding: 22px 0;
margin: 64px 0 32px 0;
font-size: 22px;
font-weight: 700;
line-height: 1.45;
letter-spacing: -0.02em;
color: var(--color-text-dark);
}
/* H3 - 좌측 세로줄 */
.entry-content h3 {
border-left: 4px solid #333;
padding: 4px 0 4px 18px;
margin: 48px 0 24px 0;
font-size: 19px;
font-weight: 700;
line-height: 1.45;
color: var(--color-text-dark);
}
.entry-content h4 {
font-size: 17px;
font-weight: 700;
margin: 36px 0 16px 0;
color: var(--color-text-dark);
}
/* 이미지 확장 */
.entry-content img,
.entry-content figure {
width: calc(100% + 200px);
max-width: calc(100% + 200px);
margin-left: -100px;
margin-right: -100px;
border-radius: 0;
}
.entry-content figure {
margin-bottom: 32px;
}
.entry-content figure img {
width: 100%;
margin-left: 0;
margin-right: 0;
}
.entry-content figcaption {
font-size: 13px;
color: var(--color-text-muted);
text-align: center;
padding: 12px 100px 0;
line-height: 1.5;
}
/* Blockquote */
.entry-content blockquote {
border-left: 4px solid var(--color-accent);
padding: 20px 24px;
margin: 36px 0;
background: #f8f8f8;
font-style: italic;
color: #555;
}
.entry-content blockquote p:last-child {
margin-bottom: 0;
}
/* Lists */
.entry-content ul,
.entry-content ol {
margin: 24px 0;
padding-left: 28px;
}
.entry-content ul {
list-style: disc;
}
.entry-content ol {
list-style: decimal;
}
.entry-content li {
margin-bottom: 8px;
line-height: 1.7;
}
/* Code */
.entry-content code {
background: #f4f4f4;
padding: 2px 6px;
border-radius: 3px;
font-size: 14px;
color: var(--color-accent);
}
.entry-content pre {
background: #1e1e1e;
color: #d4d4d4;
padding: 24px;
border-radius: 6px;
overflow-x: auto;
margin: 32px 0;
font-size: 14px;
line-height: 1.6;
}
.entry-content pre code {
background: none;
padding: 0;
border-radius: 0;
color: inherit;
font-size: inherit;
}
/* Table */
.entry-content table {
width: 100%;
border-collapse: collapse;
margin: 32px 0;
font-size: 15px;
}
.entry-content th,
.entry-content td {
padding: 12px 16px;
border: 1px solid #e0e0e0;
text-align: left;
}
.entry-content th {
background: #f5f5f5;
font-weight: 700;
}
/* WordPress Alignment */
.entry-content .alignwide {
width: calc(100% + 200px);
max-width: calc(100% + 200px);
margin-left: -100px;
}
.entry-content .alignfull {
width: 100vw;
max-width: 100vw;
margin-left: calc(-50vw + 50%);
}
.entry-content .aligncenter {
display: block;
margin-left: auto;
margin-right: auto;
text-align: center;
}
.entry-content .alignleft {
float: left;
margin: 0 24px 16px 0;
width: auto;
max-width: 50%;
}
.entry-content .alignright {
float: right;
margin: 0 0 16px 24px;
width: auto;
max-width: 50%;
}
/* WP Block Image - 기본 이미지도 확장 */
.entry-content .wp-block-image {
width: calc(100% + 200px);
max-width: calc(100% + 200px);
margin-left: -100px;
margin-right: -100px;
}
.entry-content .wp-block-image img {
width: 100%;
margin-left: 0;
margin-right: 0;
}
.entry-content .wp-block-image figcaption {
padding: 12px 100px 0;
}
/* Post Navigation */
.post-navigation {
margin-top: 60px;
padding-top: 40px;
border-top: 1px solid #eee;
}
.nav-links {
display: flex;
justify-content: space-between;
gap: 30px;
}
.nav-previous,
.nav-next {
flex: 1;
display: flex;
flex-direction: column;
gap: 6px;
padding: 16px 0;
transition: color var(--transition-fast);
}
.nav-next {
text-align: right;
}
.nav-label {
font-size: 12px;
font-weight: 600;
color: var(--color-text-muted);
text-transform: uppercase;
letter-spacing: 0.05em;
}
.nav-title {
font-size: 15px;
font-weight: 600;
color: var(--color-text-dark);
display: -webkit-box;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
overflow: hidden;
}
.nav-previous:hover .nav-title,
.nav-next:hover .nav-title {
color: var(--color-accent);
}
/* Comments */
.comments-area-wrapper {
margin-top: 60px;
padding-top: 40px;
border-top: 1px solid #eee;
}
.comments-title {
font-size: 20px;
font-weight: 700;
margin-bottom: 30px;
color: var(--color-text-dark);
}
.comment-list {
list-style: none;
}
.comment-list .comment {
padding: 24px 0;
border-bottom: 1px solid #f0f0f0;
}
.comment-list .comment-body {
display: flex;
gap: 16px;
}
.comment-list .comment-author img {
border-radius: 50%;
}
.comment-list .comment-content p {
font-size: 15px;
line-height: 1.6;
color: var(--color-text-body);
}
/* Comment Form */
.comment-respond {
margin-top: 40px;
}
.comment-respond .comment-reply-title {
font-size: 20px;
font-weight: 700;
margin-bottom: 20px;
}
.comment-respond .comment-form p {
margin-bottom: 16px;
}
.comment-respond .comment-form label {
display: block;
font-size: 13px;
font-weight: 600;
color: var(--color-text-muted);
margin-bottom: 6px;
}
.comment-respond .comment-form input[type="text"],
.comment-respond .comment-form input[type="email"],
.comment-respond .comment-form input[type="url"],
.comment-respond .comment-form textarea {
width: 100%;
padding: 12px 16px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 15px;
font-family: var(--font-primary);
transition: border-color var(--transition-fast);
}
.comment-respond .comment-form input:focus,
.comment-respond .comment-form textarea:focus {
outline: none;
border-color: var(--color-text-dark);
}
.comment-respond .comment-form textarea {
min-height: 150px;
resize: vertical;
}
.comment-respond .form-submit .submit {
background: var(--color-text-dark);
color: #fff;
border: none;
padding: 14px 36px;
font-size: 14px;
font-weight: 600;
border-radius: 4px;
cursor: pointer;
transition: background var(--transition-fast);
}
.comment-respond .form-submit .submit:hover {
background: #000;
}
/* Related Posts Section (Full Width) */
.related-posts-section {
width: 100vw;
margin-left: calc(-50vw + 50%);
background: var(--color-bg-dark);
padding: 80px 40px;
margin-top: 80px;
}
.related-posts-inner {
max-width: var(--site-max-width);
margin: 0 auto;
}
.related-title {
font-size: 28px;
font-weight: 700;
color: var(--color-text-primary);
text-align: center;
margin-bottom: 40px;
}
.related-posts-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: var(--grid-gap);
}
21. assets/css/archive.css
/* ========== ARCHIVE / SEARCH ========== */
/* archive.php와 search.php는 front-page.css의 .main-hero-section 스타일을 공유 */
/* 추가적인 아카이브 전용 스타일 */
.archive .main-section-title,
.search .main-section-title {
font-family: var(--font-primary);
font-size: 36px;
}
22. assets/css/responsive.css
/* ========== RESPONSIVE ========== */
/* Tablet Large */
@media (max-width: 1200px) {
.posts-grid,
.related-posts-grid {
grid-template-columns: repeat(3, 1fr);
}
}
/* Tablet */
@media (max-width: 1024px) {
:root {
--section-padding: 60px 30px;
}
.header-inner {
padding: 0 24px;
}
.main-hero-section {
padding: 100px 30px 60px;
}
.main-section-title {
font-size: 40px;
}
.single-title {
font-size: 32px;
}
.hero-content {
padding: 40px 40px 50px;
}
.hero-actions {
bottom: 50px;
right: 40px;
}
.posts-grid,
.related-posts-grid {
grid-template-columns: repeat(2, 1fr);
}
.related-posts-section {
padding: 60px 30px;
}
}
/* Mobile Large */
@media (max-width: 768px) {
.main-navigation {
display: none;
}
.menu-toggle {
display: flex;
}
/* Mobile Menu */
.main-navigation.toggled {
display: flex;
flex-direction: column;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.98);
z-index: 9998;
justify-content: center;
align-items: center;
animation: fadeIn 0.3s ease;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
.main-navigation.toggled .primary-menu {
flex-direction: column;
gap: 4px;
text-align: center;
}
.main-navigation.toggled .primary-menu li a {
font-size: 20px;
padding: 14px 28px;
}
.main-navigation.toggled .primary-menu li .sub-menu {
position: static;
transform: none;
opacity: 1;
visibility: visible;
background: transparent;
box-shadow: none;
padding: 0;
min-width: auto;
}
/* Hero */
.single-hero {
min-height: 60vh;
}
.hero-content {
padding: 30px 24px 40px;
}
.single-title {
font-size: 26px;
}
.hero-actions {
position: static;
margin-top: 20px;
}
/* Content */
.single-content-wrapper {
padding: 40px 20px 60px;
}
.entry-content {
font-size: 16px;
}
.entry-content h2 {
font-size: 20px;
margin: 48px 0 24px;
}
.entry-content h3 {
font-size: 17px;
margin: 36px 0 18px;
}
/* 모바일에서 이미지 확장 축소 */
.entry-content img,
.entry-content figure,
.entry-content .wp-block-image,
.entry-content .alignwide {
width: calc(100% + 40px);
max-width: calc(100% + 40px);
margin-left: -20px;
margin-right: -20px;
}
.entry-content figcaption,
.entry-content .wp-block-image figcaption {
padding: 10px 20px 0;
}
/* Grid */
.main-hero-section {
padding: 90px 20px 50px;
}
.main-section-title {
font-size: 32px;
}
.category-filter {
gap: 16px;
margin-bottom: 36px;
}
.filter-tab {
font-size: 13px;
}
.posts-grid,
.related-posts-grid {
grid-template-columns: repeat(2, 1fr);
gap: 16px;
}
.card-title {
font-size: 14px;
}
.related-posts-section {
padding: 50px 20px;
}
.related-title {
font-size: 24px;
}
/* Navigation */
.nav-links {
flex-direction: column;
gap: 16px;
}
.nav-next {
text-align: left;
}
}
/* Mobile Small */
@media (max-width: 480px) {
.posts-grid,
.related-posts-grid {
grid-template-columns: 1fr;
gap: 20px;
}
.main-section-title {
font-size: 28px;
}
.single-hero {
min-height: 50vh;
}
.single-title {
font-size: 22px;
}
.header-inner {
padding: 0 16px;
height: 60px;
}
.category-filter {
gap: 12px;
}
.filter-tab {
font-size: 12px;
}
}
/* Footer Responsive */
@media (max-width: 768px) {
.footer-top {
flex-direction: column;
gap: 30px;
}
.footer-widgets {
flex-direction: column;
}
}
23. assets/js/navigation.js
/**
* H-Style Navigation
* 스크롤 감지 + 모바일 메뉴 + 검색 오버레이
*/
(function () {
'use strict';
const header = document.getElementById('masthead');
const menuToggle = document.querySelector('.menu-toggle');
const navigation = document.getElementById('site-navigation');
const searchToggle = document.querySelector('.search-toggle');
const searchOverlay = document.querySelector('.search-overlay');
const searchClose = document.querySelector('.search-close');
const searchField = document.querySelector('.search-overlay .search-field');
const backToTop = document.querySelector('.back-to-top');
/**
* Header Scroll Effect
*/
let lastScroll = 0;
const scrollThreshold = 50;
function handleScroll() {
const currentScroll = window.pageYOffset;
if (currentScroll > scrollThreshold) {
header.classList.add('scrolled');
} else {
header.classList.remove('scrolled');
}
lastScroll = currentScroll;
}
window.addEventListener('scroll', handleScroll, { passive: true });
handleScroll(); // Initial check
/**
* Mobile Menu Toggle
*/
if (menuToggle && navigation) {
menuToggle.addEventListener('click', function () {
const isExpanded = menuToggle.getAttribute('aria-expanded') === 'true';
menuToggle.setAttribute('aria-expanded', !isExpanded);
navigation.classList.toggle('toggled');
document.body.style.overflow = navigation.classList.contains('toggled') ? 'hidden' : '';
});
// Close on menu item click
const menuLinks = navigation.querySelectorAll('.primary-menu > li > a');
menuLinks.forEach(function (link) {
link.addEventListener('click', function () {
if (navigation.classList.contains('toggled')) {
navigation.classList.remove('toggled');
menuToggle.setAttribute('aria-expanded', 'false');
document.body.style.overflow = '';
}
});
});
}
/**
* Search Overlay
*/
if (searchToggle && searchOverlay) {
searchToggle.addEventListener('click', function () {
searchOverlay.classList.add('active');
searchOverlay.setAttribute('aria-hidden', 'false');
document.body.style.overflow = 'hidden';
if (searchField) {
setTimeout(function () { searchField.focus(); }, 100);
}
});
if (searchClose) {
searchClose.addEventListener('click', closeSearch);
}
searchOverlay.addEventListener('click', function (e) {
if (e.target === searchOverlay) {
closeSearch();
}
});
document.addEventListener('keydown', function (e) {
if (e.key === 'Escape' && searchOverlay.classList.contains('active')) {
closeSearch();
}
});
}
function closeSearch() {
searchOverlay.classList.remove('active');
searchOverlay.setAttribute('aria-hidden', 'true');
document.body.style.overflow = '';
}
/**
* Back to Top
*/
if (backToTop) {
backToTop.addEventListener('click', function () {
window.scrollTo({ top: 0, behavior: 'smooth' });
});
}
/**
* Fallback Menu (메뉴 미설정 시)
*/
})();
/**
* Fallback menu function (PHP에서 호출)
*/
function hstyle_fallback_menu() {
// PHP에서 처리
}
24. assets/js/load-more.js
/**
* H-Style AJAX Load More
* 더보기 버튼 & 카테고리 필터
*/
(function ($) {
'use strict';
const $grid = $('#main-posts-grid');
const $loadMoreBtn = $('.load-more-btn');
const $filterTabs = $('.filter-tab');
let isLoading = false;
let currentCategory = 'all';
/**
* Load More Button
*/
$loadMoreBtn.on('click', function () {
if (isLoading) return;
const $btn = $(this);
const page = parseInt($btn.data('page')) + 1;
const maxPages = parseInt($btn.data('max'));
const searchQuery = $btn.data('search') || '';
if (page > maxPages) return;
isLoading = true;
$btn.addClass('loading');
$.ajax({
url: hstyleAjax.ajaxurl,
type: 'POST',
data: {
action: 'hstyle_load_more',
nonce: hstyleAjax.nonce,
page: page,
category: currentCategory !== 'all' ? currentCategory : '',
search: searchQuery,
},
success: function (response) {
if (response.success && response.data.html) {
const $newItems = $(response.data.html);
$newItems.css('opacity', 0);
$grid.append($newItems);
// Fade in animation
requestAnimationFrame(function () {
$newItems.css({
'opacity': 1,
'transition': 'opacity 0.4s ease',
});
});
$btn.data('page', page);
if (page >= maxPages || !response.data.has_more) {
$btn.parent('.load-more-wrapper').fadeOut(300);
}
} else {
$btn.parent('.load-more-wrapper').fadeOut(300);
}
},
error: function () {
console.error('Load more failed');
},
complete: function () {
isLoading = false;
$btn.removeClass('loading');
},
});
});
/**
* Category Filter Tabs
*/
$filterTabs.on('click', function () {
if (isLoading) return;
const $tab = $(this);
const category = $tab.data('category');
if (category === currentCategory) return;
// Update active state
$filterTabs.removeClass('active').attr('aria-selected', 'false');
$tab.addClass('active').attr('aria-selected', 'true');
currentCategory = category;
isLoading = true;
// Fade out current
$grid.css('opacity', 0.3);
$.ajax({
url: hstyleAjax.ajaxurl,
type: 'POST',
data: {
action: 'hstyle_filter_posts',
nonce: hstyleAjax.nonce,
category: category !== 'all' ? category : '',
},
success: function (response) {
if (response.success && response.data.html) {
$grid.html(response.data.html);
// Reset load more
$loadMoreBtn.data('page', 1);
$loadMoreBtn.data('max', response.data.max_pages);
if (response.data.max_pages > 1) {
$loadMoreBtn.parent('.load-more-wrapper').fadeIn(300);
} else {
$loadMoreBtn.parent('.load-more-wrapper').fadeOut(300);
}
}
},
complete: function () {
isLoading = false;
$grid.css({ 'opacity': 1, 'transition': 'opacity 0.4s ease' });
},
});
});
})(jQuery);
25. assets/js/hero-scroll.js
/**
* H-Style Hero Parallax & Scroll Effects
* 싱글 포스트 히어로 패럴랙스
*/
(function () {
'use strict';
const hero = document.querySelector('.single-hero');
if (!hero) return;
const heroContent = hero.querySelector('.hero-content');
// Parallax on scroll
function handleParallax() {
const scrollY = window.pageYOffset;
const heroHeight = hero.offsetHeight;
if (scrollY <= heroHeight) {
const ratio = scrollY / heroHeight;
hero.style.backgroundPositionY = (50 + ratio * 20) + '%';
if (heroContent) {
heroContent.style.opacity = 1 - ratio * 1.2;
heroContent.style.transform = 'translateY(' + (scrollY * 0.3) + 'px)';
}
}
}
// Use requestAnimationFrame for smooth performance
let ticking = false;
window.addEventListener('scroll', function () {
if (!ticking) {
requestAnimationFrame(function () {
handleParallax();
ticking = false;
});
ticking = true;
}
}, { passive: true });
})();
26. inc/customizer.php
<?php
/**
* Theme Customizer
*
* @package H-Style
*/
function hstyle_customize_register($wp_customize) {
// 테마 옵션 패널
$wp_customize->add_panel('hstyle_options', array(
'title' => __('H-Style 테마 설정', 'h-style'),
'priority' => 30,
));
/**
* 일반 설정
*/
$wp_customize->add_section('hstyle_general', array(
'title' => __('일반 설정', 'h-style'),
'panel' => 'hstyle_options',
'priority' => 10,
));
// 액센트 컬러
$wp_customize->add_setting('hstyle_accent_color', array(
'default' => '#e63946',
'sanitize_callback' => 'sanitize_hex_color',
'transport' => 'postMessage',
));
$wp_customize->add_control(new WP_Customize_Color_Control($wp_customize, 'hstyle_accent_color', array(
'label' => __('액센트 색상', 'h-style'),
'section' => 'hstyle_general',
)));
// 다크 배경 컬러
$wp_customize->add_setting('hstyle_dark_bg_color', array(
'default' => '#111111',
'sanitize_callback' => 'sanitize_hex_color',
'transport' => 'postMessage',
));
$wp_customize->add_control(new WP_Customize_Color_Control($wp_customize, 'hstyle_dark_bg_color', array(
'label' => __('다크 배경 색상', 'h-style'),
'section' => 'hstyle_general',
)));
/**
* 메인 페이지 설정
*/
$wp_customize->add_section('hstyle_frontpage', array(
'title' => __('메인 페이지', 'h-style'),
'panel' => 'hstyle_options',
'priority' => 20,
));
// 메인 타이틀
$wp_customize->add_setting('hstyle_main_title', array(
'default' => "WHAT'S NEW",
'sanitize_callback' => 'sanitize_text_field',
));
$wp_customize->add_control('hstyle_main_title', array(
'label' => __('메인 섹션 타이틀', 'h-style'),
'section' => 'hstyle_frontpage',
'type' => 'text',
));
// 글 개수
$wp_customize->add_setting('hstyle_posts_per_load', array(
'default' => 8,
'sanitize_callback' => 'absint',
));
$wp_customize->add_control('hstyle_posts_per_load', array(
'label' => __('더보기 시 로드할 글 수', 'h-style'),
'section' => 'hstyle_frontpage',
'type' => 'number',
'input_attrs' => array('min' => 4, 'max' => 20, 'step' => 1),
));
/**
* 싱글 포스트 설정
*/
$wp_customize->add_section('hstyle_single', array(
'title' => __('글 보기 설정', 'h-style'),
'panel' => 'hstyle_options',
'priority' => 30,
));
// 관련글 표시
$wp_customize->add_setting('hstyle_show_related', array(
'default' => true,
'sanitize_callback' => 'hstyle_sanitize_checkbox',
));
$wp_customize->add_control('hstyle_show_related', array(
'label' => __('관련글 표시', 'h-style'),
'section' => 'hstyle_single',
'type' => 'checkbox',
));
// 관련글 개수
$wp_customize->add_setting('hstyle_related_count', array(
'default' => 4,
'sanitize_callback' => 'absint',
));
$wp_customize->add_control('hstyle_related_count', array(
'label' => __('관련글 개수', 'h-style'),
'section' => 'hstyle_single',
'type' => 'number',
'input_attrs' => array('min' => 2, 'max' => 8, 'step' => 1),
));
/**
* 푸터 설정
*/
$wp_customize->add_section('hstyle_footer', array(
'title' => __('푸터 설정', 'h-style'),
'panel' => 'hstyle_options',
'priority' => 40,
));
// 저작권 텍스트
$wp_customize->add_setting('hstyle_copyright', array(
'default' => '',
'sanitize_callback' => 'wp_kses_post',
));
$wp_customize->add_control('hstyle_copyright', array(
'label' => __('저작권 텍스트', 'h-style'),
'section' => 'hstyle_footer',
'type' => 'textarea',
));
}
add_action('customize_register', 'hstyle_customize_register');
/**
* 커스텀 CSS 출력
*/
function hstyle_customizer_css() {
$accent = get_theme_mod('hstyle_accent_color', '#e63946');
$dark_bg = get_theme_mod('hstyle_dark_bg_color', '#111111');
$css = "
:root {
--color-accent: {$accent};
--color-bg-dark: {$dark_bg};
}
";
wp_add_inline_style('hstyle-main', $css);
}
add_action('wp_enqueue_scripts', 'hstyle_customizer_css', 20);
/**
* Sanitize Checkbox
*/
function hstyle_sanitize_checkbox($checked) {
return ((isset($checked) && true == $checked) ? true : false);
}
27. inc/template-tags.php
<?php
/**
* Template Tags
*
* @package H-Style
*/
/**
* 폴백 메뉴
*/
function hstyle_fallback_menu() {
echo '<ul class="primary-menu">';
echo '<li><a href="' . esc_url(home_url('/')) . '">' . esc_html__('홈', 'h-style') . '</a></li>';
$categories = get_categories(array(
'orderby' => 'count',
'order' => 'DESC',
'number' => 5,
));
foreach ($categories as $cat) {
echo '<li><a href="' . esc_url(get_category_link($cat->term_id)) . '">' . esc_html($cat->name) . '</a></li>';
}
echo '</ul>';
}
/**
* 읽기 시간 계산
*/
function hstyle_reading_time($post_id = null) {
if (!$post_id) $post_id = get_the_ID();
$content = get_post_field('post_content', $post_id);
$word_count = mb_strlen(strip_tags($content));
$reading_time = ceil($word_count / 500); // 한국어 약 500자/분
return max(1, $reading_time);
}
/**
* 조회수 (간단 구현)
*/
function hstyle_get_post_views($post_id = null) {
if (!$post_id) $post_id = get_the_ID();
$count = get_post_meta($post_id, 'hstyle_post_views', true);
return $count ? number_format($count) : '0';
}
function hstyle_set_post_views($post_id = null) {
if (!$post_id) $post_id = get_the_ID();
$count = (int) get_post_meta($post_id, 'hstyle_post_views', true);
update_post_meta($post_id, 'hstyle_post_views', $count + 1);
}
// 싱글 페이지 조회수 증가
function hstyle_track_views() {
if (is_singular('post') && !is_admin()) {
hstyle_set_post_views(get_the_ID());
}
}
add_action('wp', 'hstyle_track_views');
/**
* 아카이브 제목 필터 (접두사 제거)
*/
function hstyle_archive_title($title) {
if (is_category()) {
$title = single_cat_title('', false);
} elseif (is_tag()) {
$title = '#' . single_tag_title('', false);
} elseif (is_author()) {
$title = get_the_author();
} elseif (is_year()) {
$title = get_the_date('Y');
} elseif (is_month()) {
$title = get_the_date('Y.m');
} elseif (is_day()) {
$title = get_the_date('Y.m.d');
}
return $title;
}
add_filter('get_the_archive_title', 'hstyle_archive_title');
28. inc/ajax-load-more.php
<?php
/**
* AJAX Load More & Filter
*
* @package H-Style
*/
/**
* Load More Posts
*/
function hstyle_load_more_handler() {
check_ajax_referer('hstyle_load_more', 'nonce');
$page = isset($_POST['page']) ? absint($_POST['page']) : 1;
$category = isset($_POST['category']) ? sanitize_text_field($_POST['category']) : '';
$search = isset($_POST['search']) ? sanitize_text_field($_POST['search']) : '';
$per_page = get_option('posts_per_page', 8);
$args = array(
'posts_per_page' => $per_page,
'paged' => $page,
'post_status' => 'publish',
'ignore_sticky_posts' => true,
);
if ($category) {
$args['category_name'] = $category;
}
if ($search) {
$args['s'] = $search;
}
$query = new WP_Query($args);
ob_start();
if ($query->have_posts()) {
while ($query->have_posts()) {
$query->the_post();
get_template_part('template-parts/content', 'card');
}
}
$html = ob_get_clean();
wp_reset_postdata();
wp_send_json_success(array(
'html' => $html,
'has_more' => $page < $query->max_num_pages,
'max_pages' => $query->max_num_pages,
));
}
add_action('wp_ajax_hstyle_load_more', 'hstyle_load_more_handler');
add_action('wp_ajax_nopriv_hstyle_load_more', 'hstyle_load_more_handler');
/**
* Filter Posts by Category
*/
function hstyle_filter_posts_handler() {
check_ajax_referer('hstyle_load_more', 'nonce');
$category = isset($_POST['category']) ? sanitize_text_field($_POST['category']) : '';
$per_page = get_option('posts_per_page', 8);
$args = array(
'posts_per_page' => $per_page,
'post_status' => 'publish',
'ignore_sticky_posts' => true,
);
if ($category) {
$args['category_name'] = $category;
}
$query = new WP_Query($args);
ob_start();
if ($query->have_posts()) {
while ($query->have_posts()) {
$query->the_post();
get_template_part('template-parts/content', 'card');
}
} else {
get_template_part('template-parts/content', 'none');
}
$html = ob_get_clean();
wp_reset_postdata();
wp_send_json_success(array(
'html' => $html,
'max_pages' => $query->max_num_pages,
));
}
add_action('wp_ajax_hstyle_filter_posts', 'hstyle_filter_posts_handler');
add_action('wp_ajax_nopriv_hstyle_filter_posts', 'hstyle_filter_posts_handler');
설치 방법
1단계: 위의 파일 구조대로 폴더와 파일을 생성합니다.
2단계: h-style 폴더를 압축하여 h-style.zip 파일로 만듭니다.
3단계: 워드프레스 관리자 → 외모 → 테마 → 새로 추가 → 테마 업로드에서 zip 파일을 업로드합니다.
4단계: 테마를 활성화한 뒤 다음을 설정합니다:
- 외모 → 메뉴: 주 내비게이션 메뉴를 생성하고 "주 내비게이션" 위치에 지정
- 외모 → 사용자 정의하기 → H-Style 테마 설정: 액센트 색상, 메인 타이틀 등 조정
- 설정 → 읽기: 홈페이지 표시를 "최근 글"로 설정하거나, "정적 페이지"로 설정 후 프론트 페이지 지정
- 각 글에 대표 이미지(Featured Image) 설정: 히어로 영역에 표시됩니다
이 테마에는 참고하신 SK Hynix Newsroom의 핵심 디자인 요소가 모두 포함되어 있습니다. 커스터마이저를 통해 색상이나 글 개수 등을 쉽게 조정할 수 있고, 추가로 세부 스타일을 수정하고 싶으시면 말씀해주세요.