본문으로 건너뛰기
TubePress — 무료, 자체 호스팅 & 지속 관리
디자인 및 테마

테마 개발

나만의 테마 만들기: 구조, theme.json, functions.php, 템플릿 및 헬퍼를 다룹니다.

TubePress 테마는 PHP 템플릿과 선택적 애셋 및 헬퍼 함수로 구성된 폴더입니다. 외관(Appearance)과 테마 편집기만으로는 부족하고 마크업을 완전히 제어하고 싶을 때 커스텀 테마를 사용하세요. 이 페이지는 빌드 가이드이며, 변수 및 헬퍼의 전체 목록은 테마 API 레퍼런스를 함께 참고하세요.

전반적인 황금 규칙: 값을 하드코딩하지 말고 TubePress가 주입하는 설정을 읽으세요. $_ 접두사가 붙은 변수를 준수하면, 번들 테마인 Simply와 마찬가지로 어드민에서 완전히 설정 가능한 테마를 만들 수 있습니다.

테마 구조

테마는 themes/{slug}/ 아래에 위치합니다. theme.jsontemplates/layout.php만 반드시 필요하며 — 나머지는 선택 사항이며 Simply로 폴백됩니다.

themes/aurora/
├── theme.json            Required — metadata
├── functions.php         Enqueue assets, helper functions
├── assets/
│   ├── css/style.css
│   └── js/app.js
└── templates/
    ├── layout.php        Required — the HTML shell
    ├── home.php          Homepage
    ├── video.php         Watch page
    ├── category.php      …tag/performer/channel (+ plurals)
    ├── search.php        Search results
    ├── page.php          Static page
    ├── favorites.php     User favourites
    ├── history.php       Watch history
    ├── 404.php           Not found
    ├── auth/             login, register, profile
    └── partials/
        └── video-card.php  Reusable card partial

theme.json

이 매니페스트는 필수입니다. 테마의 메타데이터, 선택적 기본 색상 세트, 그리고 임의의 settings를 포함합니다. name, version, author/admin/themes에 표시됩니다.

{
    "name": "Aurora",
    "description": "A custom theme for TubePress",
    "version": "1.0.0",
    "author": "Your Name",
    "screenshot": "screenshot.png",
    "colors": {
        "primary": "#2563eb",
        "secondary": "#7c3aed",
        "background": "#ffffff",
        "text": "#1e293b"
    },
    "settings": {
        "videos_per_row": 4
    }
}

functions.php

이 파일은 부팅 시 자동으로 로드됩니다. 스타일시트와 스크립트를 큐에 추가하고 템플릿에서 호출하는 헬퍼 함수를 정의하는 데 사용하세요. 브라우저가 항상 최신 편집 내용을 가져가도록 filemtime() 쿼리 문자열과 함께 애셋을 큐에 추가하세요. 두 번째 인수는 로드 우선순위입니다(낮을수록 먼저 로드됩니다).

<?php
declare(strict_types=1);

// filemtime() busts the cache on every edit.
$cssVer = @filemtime(ThemeManager::themePath()
    . '/assets/css/style.css') ?: time();
$jsVer  = @filemtime(ThemeManager::themePath()
    . '/assets/js/app.js') ?: time();

ThemeRenderer::enqueueCSS(
    ThemeManager::assetUrl('css/style.css') . '?v=' . $cssVer, 1);
ThemeRenderer::enqueueJS(
    ThemeManager::assetUrl('js/app.js') . '?v=' . $jsVer, 1);

// A reusable video-card helper, called from listing templates.
function auroraVideoCard(array $video): string
{
    // Record an impression so the CTR system can rank this card.
    ImpressionTracker::collect((int) $video['id']);

    // Let a plugin replace the card entirely if it wants to.
    $card = HookSystem::applyFilter('video.card.html', '', $video);
    if ($card !== '') {
        return $card;
    }

    ob_start();
    require ThemeManager::templatePath('partials/video-card');
    return ob_get_clean();
}

Simply는 simplyVideoCard()와 같은 헬퍼를 simplyPagination(), simplySortTabs()와 함께 정확히 이 방식으로 정의합니다. ImpressionTracker::collect() 호출이 CTR 랭킹을 공급하며, 배치 쓰기는 나중에 layout.php에서 플러시됩니다.

카드에는 파셜을 사용하세요. 위와 같이 ThemeManager::templatePath()와 출력 버퍼링을 사용해 partials/video-card.php를 렌더링하세요. 마크업을 한 곳에 유지하고 video.card.html 필터를 통해 플러그인이 재정의할 수 있게 합니다.

템플릿 및 렌더링 흐름

컨트롤러가 ThemeRenderer::render($template, $data)에 데이터를 전달하면, 렌더러가 그 이후를 처리합니다. 순서를 이해하면 어디서 무엇을 사용할 수 있는지 알 수 있습니다.

  1. 컨트롤러가 렌더링합니다. 예: ThemeRenderer::render('home', ['videos' => $videos]).
  2. 전역 변수가 주입됩니다. $_ 접두사가 붙은 사이트, 외관, 로케일, 카드/시청 변수가 추가됩니다.
  3. 플러그인이 데이터를 조정합니다. theme.template_data 필터가 실행되며 ($data, $templateName)을 받습니다.
  4. 템플릿이 버퍼링됩니다. 템플릿 파일이 $content로 캡처됩니다.
  5. 레이아웃이 로드됩니다. layout.php$content와 모든 변수를 받아 전체 HTML 셸을 출력합니다.
  6. 노출이 플러시됩니다. ImpressionTracker::flush()</body> 이전에 배치된 CTR 업데이트를 씁니다.
  7. Cron이 실행됩니다. CronManager::run()이 예정된 작업을 실행합니다.

layout.php는 셸을 담당합니다: <head>ThemeRenderer::renderCSS()$_colorOverrides를 포함하고, $content를 에코한 다음, </body> 이전에 ThemeRenderer::renderJS()ImpressionTracker::flush()를 호출하세요. 테마 API에서 8가지 체크리스트 전체를 확인할 수 있습니다.

전역 변수 및 헬퍼

모든 템플릿은 전역 $_ 변수와 자체 데이터를 받습니다. 테마 API 레퍼런스에 모든 변수가 문서화되어 있으며, 여기서는 가장 자주 사용하는 것들을 소개합니다.

자주 사용되는 변수용도
$_siteName, $_siteUrl, $_user사이트 정체성 및 로그인한 사용자(또는 null).
$_videosPerRow목록의 그리드 열 수 (4, 5 또는 6).
$_colorOverrides<head>에 삽입할 색상 사용자 정의 속성의 <style> 블록.
$_card*, $_watch*외관(Appearance)에서 설정한 카드 및 시청 페이지 토글.
$_menuItems, $_menuSearch탐색 항목 및 검색 바 토글.
주요 헬퍼용도
ThemeRenderer::enqueueCSS/::enqueueJS, ::partial, ::renderCSS/::renderJS.
ThemeManager::assetUrl, ::themePath, ::templatePath, ::active.
Format표시를 위한 ::number, ::duration, ::timeAgo.
Router / url()URL 생성, 폼용 ::csrfField().
Setting, __()설정 읽기; 키 번역.

템플릿 폴백

활성화된 테마에 템플릿이 없으면, TubePress는 Simply의 복사본을 대신 렌더링합니다. 즉, 변경하고 싶은 것만 재정의하면 됩니다. 예를 들어 home.php를 테마에 복사하는 것부터 시작하고, 준비될 때까지 나머지는 Simply에서 상속받으세요. 테마는 파일 하나일 수도 있고 오십 개일 수도 있습니다.

테마 훅

템플릿 외에도 소수의 훅 포인트를 통해 페이지를 포크하지 않고 확장할 수 있습니다(플러그인도 가능). 액션은 실행 후 잊어버리고, 필터는 반환하는 값을 변환합니다.

유형용도
head.meta액션<head> 안에 태그를 출력합니다 (meta, JSON-LD, 인증).
footer.scripts액션</body> 직전에 마크업을 출력합니다.
video.card.html필터카드의 HTML을 교체합니다. 인수 ($html, $video); 재정의하려면 비어 있지 않은 문자열을 반환하세요.
// An action — fire and forget, inside <head>.
HookSystem::doAction('head.meta');

// A filter — return '' to keep the default card.
HookSystem::addFilter('video.card.html',
    function (string $html, array $video): string {
        return $html;
    });

알아 둘 만한 필터가 두 가지 더 있습니다: 렌더링 전 데이터 배열을 조정하는 theme.template_data<style> 문자열을 추가하는 head.css — Simply는 후자를 사용해 그리드 간격과 반경을 CSS 변수로 게시합니다. 더 넓은 액션/필터 카탈로그는 훅 & 플러그인을 참고하세요.

다음 단계

여전히 막히셨나요?

대시보드에서 티켓을 열면 저희 팀이 도와드리겠습니다.

라이브 데모 체험하기 → TubePress 다운로드 →