← home

워드프레스 – 코드플로우(URL에서 페이지까지)

워드프레스로 만든 웹사이트에 접속했을 때, 어떠한 과정을 거쳐 최종 결과물(페이지)이 화면에 나타나는게 되는지, 즉 워드프레스의 코드 플로우를 살펴보고자 합니다.

제가 처음 워드프레스 개발에 입문하였을 때(버전 2.8), 부족한 영어실력 탓인지, 개발능력 탓인지… 책 몇 권을 읽어보아도 전체적인 흐름을 머리속에 그리기가 쉽지 않았습니다. 당시 플러그인과 테마를 직접 개발하여 웹사이트를 만들고 있었음에도 말이죠. 그래서 틈나는대로 주요한 코어 파일들을 열어보며 흐름을 파악하기 위해 노력했던 기억이 있습니다.
오늘 이 포스트를 작성하기 전에 ‘WordPress code flow’로 검색을 해보니 정확히 같은 제목의 아티클이 있더군요. http://codex.wordpress.org/User:DavidHouse/Wordpress_Code_Flow
제가 작성하려는 내용과 거의 비슷해서 그냥 번역을 해볼까 했지만, 너무 오래된 버전(1.5)에 대한 내용이어서 좀 더 자세한 설명과 함께 내용을 정리해보기로 하였습니다.

* 이 문서는 3.9 버전을 기준으로 설명합니다.

우선 큰 흐름을 먼저 살펴봅시다.

index.php
↓
wp-blog-header.php → wp-load.php
↓                    ↓
↓                    wp-config.php  // DB 정보, 인증키, 절대경로 등 중요한 변/상수 설정
↓                    ↓
↓                    wp-settings.php  // 중요 자원 로드, 환경 설정
↓
wp();  // 워드프레스 메인쿼리
↓
wp-includes/template-loader.php  // 템플릿 로드

 

index.php

Front-End에서 눈에 보이는 모든 워드프레스 페이지들의 스크립트 파일은 워드프레스가 설치된 디렉토리의 index.php 파일입니다. 이 파일에는 단 두 줄의 코드가 들어있습니다.

define('WP_USE_THEMES', true);
require( dirname( __FILE__ ) . '/wp-blog-header.php' );

라인 1. WP_USE_THEMES 상수는 템플릿 리다이렉트/로드를 할 것인지를 설정.
라인 2. 워드프레스 환경과 템플릿 로드.

WP_USE_THEMES 상수 활용(참고사항으로서 건너뛰어도 됩니다.)
이 상수의 기능(템플릿 리다이렉트/로드를 할지 말지)은 잘 알고 있지만, 어떤 경우에 ‘false’를 설정하여 활용하는지는 잘 알지 못해서 검색을 해보았습니다. 제가 원하는 정확한 답을 찾기 힘들었지만 ‘워드프레스 밖에서 워드프레스를 실행하기 위한 목적’이라는 의견들이 눈에 띄었습니다.(‘워드프레스 밖에서’라는 말은 지금 우리가 살펴보고있는 Front-End에서 워드프레스 플로우가 아닌 상황을 말하는 것 같습니다.) 하지만 이런 경우에도 이 상수를 사용하는 일은 없습니다. 워드프레스 밖에서 워드프레스를 실행하기 위해서는 부트스트랩 파일인 wp-load.php 파일만 로드하면 되거든요. 예를들어 wp-admin/admin-ajax.php 같은 파일을 열어보면, WP_USE_THEMES 설정없이 wp-load.php만 로드하여 워드프레스를 실행하는 것을 확인할 수 있습니다.
비록 쓸모 없어보이는 녀석이지만, 괜히 처음부터 등장하는 것은 아니리라는 마음으로 좀 더 고민해보았습니다.
워드프레스 Release Archive에서 주요 버전을 다운받아서, 언제부터 이 상수가 사용되기 시작했는지 찾아보았더니 2.6버전부터 였습니다. 그 이전 버전과의 눈에 띄는 차이는 wp-load.php 파일의 존재이더군요. 아, 이 상수는 이 파일과 관계가 있는 것 같습니다. 기존에는 부트스트랩 파일이 따로 분리되어있지 않고, wp-blog-header.php에서 직접 워드프레스 환경과 템플릿을 직접 불러왔기 때문에 템플릿 리다이렉트/로드를 할지 말지를 미리 결정해주어야했던 것입니다. 결론은… 더 이상 이 상수는 쓸모가 없고, 이렇게 길게 설명할 필요도 없었다는 결론… 다만 구버전 호환을 위해 살려두고 있는 것일 테지요. 단, 이것은 제 예상입니다.

 

 

wp-blog-header.php

wp-blog-header.php에서는 하는 일은 다음과 같습니다.
1. wp-load.php 로드,
2. 메인쿼리 실행,
3. 올바른 템플릿 로드.

 

1. wp-load.php

if ( file_exists( ABSPATH . 'wp-config.php') ) {
	require_once( ABSPATH . 'wp-config.php' );
} elseif ( file_exists( dirname(ABSPATH) . '/wp-config.php' ) && ! file_exists( dirname(ABSPATH) . '/wp-settings.php' ) ) {
	require_once( dirname(ABSPATH) . '/wp-config.php' );
} else {
	// 설치 화면
}

설정파일인 wp-config.php가 존재하지 않으면 워드프레스 설치화면이 나타나고,
파일이 존재하면 로드합니다. wp-load.php의 역할은 이것으로 끝입니다.
그런데 wp-load.php 파일의 존재여부를 체크할 때, 라인 3과 같이 상위 디렉토리에 이 파일이 있는지도 체크하고 있습니다. wp-load.php 파일에는 데이터베이스 연결정보, 인증키 등 민감한 정보를 포함하고 있기 때문에 안전을 위해 URL로 엑세스할 수 없는 상위 디렉토리로 옮겨두는 것이 좋습니다. 단, 워드프레스를 루트디렉토리에 설치한 경우에 해당되는 이야기겠지요?

 

wp-config.php

데이터베이스 접속정보, 인증키, 언어 등 중요한 변/상수를 설정하고, wp-settings.php 파일을 로드합니다.
자동 생성된 설정 이외에 다양한 상수들을 미리 설정할 수 있는데요, 유용한 상수 몇가지만 소개드리도록 하겠습니다.

CUSTOM_USER_TABLE & CUSTOM_USER_META_TABLE
사용자정의 사용자 테이블. 다른 워드프레스 사이트의 사용자 테이블을 공유할 때 매우 유용하다. 예를들어 A라는 워드프레스 사이트와 B라는 워드프레스 사이트가 있는데, B사이트가 자신의 사용자 테이블을 사용하지 않고 A사이트의 사용자 테이블을 공유하고자 할때 사용.

FORCE_SSL_ADMIN & FORCE_SSL_LOGIN
로그인과 어드민 페이지 SSL 활성화. 참고

WP_LANG_DIR & WP_LANG_URL
언어파일 디렉토리 & URL

WP_PLUGIN_DIR & WP_PLUGIN_URL
플러그인 디렉토리 & URL

WP_CONTENT_DIR & WP_CONTENT_URL
플러그인 디렉토리 & URL

WPMU_PLUGIN_DIR & WPMU_PLUGIN_URL
MU(must-use) 플러그인 디렉토리 & URL

AUTOSAVE_INTERVAL
자동저장 주기. (기본값: 60초)

WP_POST_REVISIONS
복원용 포스트 생성 개수 (기본값: true)
true: 모든 리비전 보관
false, 0: 보관하지않음
(int): (int) 만큼 보관

EMPTY_TRASH_DAYS
휴지통 비우기 (기본값: 30일)

DISABLE_WP_CRON
워드프레스 자체 크론 비활성. 리얼 크론 사용시 사용합니다. 참고

SAVEQUERIES
실행된 DB 쿼리를 저장. 디버그 목적(기본값: false)

SCRIPT_DEBUG
압축된 파일(min) Javascript/CSS 파일을 가져올지 여부. 디버그 목적(기본값: false)

DISALLOW_FILE_EDIT
어드민 영역에서 테마/플러그인 파일 편집기 사용 (기본값: false)

 

wp-settings.php

본격적으로 워드프레스 필수 자원을 로드하고 환경을 설정하는 파일로서, 워드프레스 개발자라면 반드시 꼼꼼히 살펴봐야하는 파일입니다.
워드프레스 라이브러리 로드, 기본 변/상수 초기화 및 추가 설정, Must-use 플러그인 로드, 활성화된 플러그인 로드, 언어 파일 로드, 테마 functions.php로드, 그리고 $wpdb, $wp 등의 주요 클래스의 인스턴스 생성.
특히 ‘plugins_loaded’, ‘init’ 등 주요 액션들이 실행되기 시작되며, 그 순서가 매우 중요하므로 또한 꼼꼼히 살펴보아야 합니다.

 

2. 메인쿼리 실행: wp()

wp-blog-header.php의 코드를 다시 봅시다.

require_once( dirname(__FILE__) . '/wp-load.php' );
wp();
require_once( ABSPATH . WPINC . '/template-loader.php' );

현재 라인 1번까지 진행되었고, 이제 라인 2번 wp함수를 실행합니다.
wp함수는 워드프레스 환경설정 클래스인 WP 클래스의 main 멤버함수를 실행시킵니다.
main 멤버함수는 워드프레스 환경에 필요한 모든 변수들을 설정합니다.
현재 사용자 설정, HTTP 헤더 설정, 요청 분석, 포스트 쿼리(메인쿼리), 전역변수 설정 등.

요청 분석 및 쿼리 과정:
1. URL과 $_POST, $_GET, $_SERVER 등의 전역 변수를 분석하여, 워드프레스 쿼리 변수에 올바른 값들을 할당.
2. 워드프레스 쿼리 클래스인 WP_Query를 이용하여 쿼리를 요청.
3. 워드프레스 쿼리 변수를 토대로 sql문을 완성하여 DB로부터 데이터(posts)를 가져옴. 이 과정에서 Conditional Tag(is_single, is_category 등)들이 결정됨.
4. 워드프레스 쿼리 변수와 DB로부터 가져온 데이터(posts, post 등)들을 전역변수로 할당하여 플러그인이나 테마 등에서 사용할 수 있도록 함.

 

3. 템플릿 로드: template-loader.php

현재 요청에 맞는 템플릿을 로드합니다. 현재 요청이란 wp()에 의해 분석된 요청 결과를 말합니다. 그리고 이 과정에서 결정된 Conditional Tag를 이용하여 정확한 템플릿을 가져와 화면에 출력합니다.

예를들어 다음과 같은 요청의 경우,

http://example.com/?p=1
워드프레스 쿼리 변수:
p = 1

완성된 sql문:
SELECT wp_posts.* FROM wp_posts WHERE 1=1 AND wp_posts.ID = 1 AND wp_posts.post_type = 'post' ORDER BY wp_posts.post_date DESC

Conditional Tags:
is_single = true
is_singular = true

위 경우 포스트 아이디가 ‘1’인 싱글 포스트에 대한 요청인 것을 알아차리고, 싱글 템플릿을 찾아 로드하게 될 것입니다. 이때 템플릿을 로드하는 룰을 잘 알아야 합니다.

twenty~로 시작하는 테마 디렉토리들을 각각 열어보세요. 굉장히 많은 파일들이 들어있고, 각각 파일 구성은 조금 다를 것입니다. 파일들의 이름은 제각기 의미와 규칙을 가지고 있는데요, 위에 예를 든 요청의 경우 싱글 포스트이므로 제일 먼저 single-post.php 파일이 있는지 검색합니다. 이 파일이 없으면 single.php, 그래도 없으면 마지막으로 index.php을 로드합니다. 이렇게 템플릿을 로드하는데 있어서 우선순위가 있고 모두 필수로 존재해야하는 템플릿이 아니기 때문에 각 테마마다 파일 구성이 다를 수 있는 것입니다. (단, index.php와 style.css 두개의 파일은 필수로 존재해야합니다.)
본 문서는 전체적인 플로우를 설명하는 것이 목적이므로 자세한 생략토록 하고 조만간 자세히 다루어보도록 하겠습니다. 참고

 

Themes

블로그의 도큐멘트는 일반적으로 Header, Content, Sidebar, Footer 영역으로 나뉘기 때문에, 재사용이 용이하도록 각 부분의 템플릿 역시 파일로 나누어 쉽게 가져올 수 있게 설계되어있습니다.
그럼 index.php 템플릿을 아주 단순하게 구성 해보겠습니다.

get_header();
if (have_posts()): while (have_posts()): the_post();
	the_content();
endwhile; endif;
get_sidebar();
get_footer();

라인 1. header.php 파일 로드.
라인 5. sidebar.php 파일 로드.
라인 6. footer.php 파일 로드.
라인 2~4. The Loop. ‘The Loop’는 워드프레스의 포스트(콘텐츠)를 손쉽게 디스플레이하는데 사용되는 PHP코드입니다. wp() 실행을 통해 메인쿼리 결과를 담고있는 $posts를 반복문으로 각각 출력하는 것입니다. 참고

 

 

마치며

지금까지 워드프레스 코드 플로우(URL에서 페이지까지)를 살펴보았습니다. 당장 특정한 기능을 구현하기위해 노력하기보다는 전체적인 흐름을 잘 파악하고 코어를 이해하는데 시간을 투자한다면, 결과적으로 작업시간은 단축되고, 프로젝트는 보다 탄탄해질 것입니다. 라고.. 제 자신에게 조언해봅니다.

← home