지난 시간에 이어 코어 두 번째 이야기를 준비했습니다. 이번에는 wp() 함수에서 일어나는 라우팅에 대해 알아봅니다.
URL을 입력하면 각 주소에 따라 서로 다른 콘텐츠가 나옵니다. 어떤 주소로는 단일 포스트 세부 내용이 나오고, 또다른 주소로는 아카이브 페이지가, RSS 피드가 나옵니다. 이게 어떻게 가능할까요? 이 원리를 간단히 알아봤습니다.
지난 시간에 이어 코어 두 번째 이야기를 준비했습니다. 이번에는 wp() 함수에서 일어나는 라우팅에 대해 알아봅니다.
URL을 입력하면 각 주소에 따라 서로 다른 콘텐츠가 나옵니다. 어떤 주소로는 단일 포스트 세부 내용이 나오고, 또다른 주소로는 아카이브 페이지가, RSS 피드가 나옵니다. 이게 어떻게 가능할까요? 이 원리를 간단히 알아봤습니다.
제작자들이 커스터마이즈를 염두에 두고 제작하여 여러 부분들이 흩어져 있다. 이 흐름을 잘 파악하지 않으면 커스터마이즈 개발시 갈피를 잡기 매우 어렵다. 아스트라 테마를 사용한 커스터마이즈시 이 노트를 보고 주요 흐름을 복기하는 것이 중요할 것으로 보인다.
주요 페이지 진입점은 테마의 기본인 archive.php, index.php, page.php, single.php 이며 여기서부터 테마의 흐름이 시작된다.
index.php, single.php, page.php 셋은 거의 동일한 구조이다. 단, page.php 의 본 콘텐트 함수는 astra_content_page_loop() 으로 조금 다르다.
메인 루프를 돌기 전후에 위치한 ‘astra_primary_content_top’, ‘astra_primary_content_bottom’ (액션 태그 이름과 콜백 함수 이름이 동일하다) 두 액션은 커스터마이징 전용으로 보인다. 부모에서는 이 부분에 별도로 정의하는 액션 콜백이 없다.
1. 메인 콘텐트를 출력하는 부분인 astra_content_loop, astra_content_page_loop 액션에서 보다 복잡한 레이아웃과 구조를 따라 분기하게 된다. 여기서 테마 UI 설정에서 적용된 여러 옵션을 따라 가게 될 것이다.
2. astra_content_loop, astra_content_page_loop 둘 다 기본으로 ‘Astra_Loop’이라는 루프 전용 클래스에서 콜백 처리한다. 두 함수 다 Astra_Loop::loop_markup( $is_page ) 함수를 호출한다. 페이지면 $is_page = true 인 차이점 뿐이다.
3. Astra_Loop::loop_markup() 에서 일괄적으로 main#main 태그를 출력한다. 그리고 페이지/비-페이지에 따라 다른 템플릿 조각을 부른다.
페이지:
Astra_Loop::template_parts_page().
–> template-parts/content-page.php.
비-페이지:
Astra_Loop::template_parts_post().
–> template-parts/content-single.php.
4. content-*.php 에서 article#post-<post-ID> 태그 출력됨.
페이지: template-parts/content-page.php 내에서 the_content() 함수가 호출되면서 메인 내용 출력.
비-페이지:
astra_entry_content_single() 호출.
astra_entry_content_single_template() 호출.
–> template-parts/single/single-layout.php.
5. the_content() 앞뒤로 astra_entry_content_{before,after}() 호출이 있는데, 이와 관련된 콜백은 아스트라 테마 자체에서는 발견되지 않는다. 커스터마이즈용으로 판단한다.
template-parts/blog/blog-layout.php 라는 부분이 있는데, 이것은 검색용 템플릿이다.
메인 루프를 분석하는 핵심인 클래스는 astra/inc/class-astra-loop.php 에 있는 Astra_Loop 이다. 말하자면 여기가 공략 포인트다.
워드프레스는 멀티사이트로 운용할 수 있다. 한 벌의 코어로 여러 사이트를 제작할 수 있다. 이 때 site1.example.com 같은 서브도메인이나 아니면 example.com/site1 처럼 패스로 각 사이트를 생성할 수 있으며, 약간의 수정만 거치면 각 사이트마다 독자적인 도메인 설정도 가능하다.
그러나 이 방법은 한 코어에 wp-config.php와 플러그인, 테마, 그리고 일부 DB 내용을 공유하게 된다. 즉, 완전히 분리된 사이트를 운용하게 되는 것은 아닌 것이다.
이 포스트에서는 워드프레스 싱글 사이트를 기반으로 하되 완전히 각자의 영역을 독자적으로 가지는 셋팅법을 적고자 한다. 사실 독자적인 셋팅을 가져가므로 설정에 의해 각 사이트는 싱글 사이트일 수도 있고 멀티사이트가 될 수도 있다. 단, 코어와 코어에 위치한 .htaccess 때문에 싱글사이트 전용, 혹은 멀티사이트 전용으로만 운용 가능하다. 도메인별로 .htaccess 처리가 가능하면 좋겠지만 쉽지 않아 보인다.
이 방법은 코어를 하나로 절약할 수 있다는 장점이 있다. 워드프레스 코어 API는 워낙 성숙해 있고 변화가 뚜렷하지 않기 때문에 버전간의 차이로 인한 문제가 드문 편이기 때문에 꽤 안심할만하다.
하지만 내 개인적인으로는 코어 이외에 다른 셋업들은 그냥 하나하나 설치하는 스탠드얼론 방법에 비해 이 방법이 아주 이득이 있는지는 모르겠다. 여러 사이트가 산만하게 늘어지는 것보다는 조금 정리할 수 있다는 여지가 있다는 정도? 그냥 이런 방법이 있고, 이런 응용이 가능하니 기록하는 의미로 포스팅한다.
각 도메인마다 로컬 서버인 127.0.0.1로 매핑해야 한다. 가장 간단한 방법은 /etc/hosts 파일을 편집하는 법이다. 이 포스트를 위한 예시로 a.shared.com, b.shared.com 이라는 가상의 도메인을 사용하기로 하자.
# /etc/hosts 127.0.0.1 shared.com 127.0.0.1 a.shared.com 127.0.0.1 b.shared.com
여기서는 shared 라는 디렉토리를 설명을 위한 루트 디렉토리로 한다. shared 아래에는 다음처럼 디렉토리를 설정하였다.
한 벌의 코어를 사용하기 때문에 코어를 별도의 장소에 격리한다. shared/core가 그 장소이며, 저기에 워드프레스 코어 파일을 다운로드 받는다. 아래 간단한 한 줄 다운로드 예제 코드를 첨부한다.
# 워드프레스 설치는 이 한줄로! wget https://wordpress.org/latest.tar.gz -O - | tar xzf - --strip=1 -C shared/core echo 'Completed!'
복잡한 설정이 필요한 nginx보다는 간단하게 쓸 수 있는 아파치를 선호한다. 첫번째 아파치 설정은 디렉토리 접근 허용이다.
<Directory "shared"> AllowOverride All Require all granted </Directory>
두번째는 가상호스트 설정. /etc/hosts를 위한 도메인 설정은 와일드카드가 먹히지 않지만, 다행히 아파치 가상호스트에서는 ServerAlias로 와일드카드를 설정할 수 있다. 요즘 https를 많이 사용하므로 간단하게 자가서명한 인증서를 이용해 https 방식으로도 동작하게 해 뒀다.
<VirtualHost *:80> ServerName shared.com ServerAlias *.shared.com DocumentRoot shared/core Alias /contents shared/contents </VirtualHost> <VirtualHost *:443> ServerName shared.com ServerAlias *.shared.com DocumentRoot shared/core Alias /contents shared/contents SSLEngine On SSLCertificateFile apache2/ssl/apache2.crt SSLCertificateKeyFile apache2/ssl/apache2.key </VirtualHost>
wp-config.php는 워드프레스 코어에 두어도 되고, 코어 파일이 있는 디렉토리의 하나 위에 두어도 된다. 여기서는 코어 디렉토리보다는 하나 위쪽인 shared/wp-config.php 파일을 두도록 하자. 그리고 여기서는 각 사이트를 위한 설정 파일을 인클루드한다.
<?php $host = $_SERVER['HTTP_HOST'] ?? ''; $config = __DIR__ . "/configs/{$host}.php"; if ( $host && file_exists( $config ) && is_readable( $config ) ) { require_once __DIR__ . '/configs/common.php'; require_once $config; } else { die( 'Config file is missing!' ); } /* That's all, stop editing! Happy publishing. */ /** Absolute path to the WordPress directory. */ if ( ! defined( 'ABSPATH' ) ) { define( 'ABSPATH', __DIR__ . '/' ); } /** Sets up WordPress vars and included files. */ require_once ABSPATH . 'wp-settings.php';
wp-config.php는 각 도메인마다 읽어야 할 설정 파일을 구분해서 읽도록 지시한다. 그리고 shared/config/common.php 파일에는 모든 사이트의 범용 설정을 작성할 것이다. 나는 데이터베이스를 하나로 잡고 마치 멀티사이트처럼 접두만 변경할 것이므로 접속 정보는 common.php에 작성할 것이다. 그리고 디버그 모드 같은 설정도 이곳에 공통 요소로 잡을 것이다.
<?php define( 'DB_NAME', 'database_name_here' ); define( 'DB_USER', 'username_here' ); define( 'DB_PASSWORD', 'password_here' ); define( 'DB_HOST', 'localhost' ); define( 'DB_CHARSET', 'utf8' ); define( 'DB_COLLATE', '' ); define( 'WP_DEBUG', true ); define( 'WP_DEBUG_DISPLAY', true ); define( 'WP_DEBUG_LOG', false ); define( 'WP_DISABLE_FATAL_ERROR_HANDLER', true ); define( 'SCRIPT_DEBUG', true );
그리고 shared/configs/a.shared.com.php, shared/configs/b.shared.com.php 두 파일을 적절히 생성한다.
define('AUTH_KEY', '...'); define('SECURE_AUTH_KEY', '...'); define('LOGGED_IN_KEY', '...'); define('NONCE_KEY', '...'); define('AUTH_SALT', '...'); define('SECURE_AUTH_SALT', '...'); define('LOGGED_IN_SALT', '...'); define('NONCE_SALT', '...'); $table_prefix = 'a_'
각 KEY, SALT는 https://api.wordpress.org/secret-key/1.1/salt/ 에서 적절히 생성한 것을 사용한다. 개발 설정에서는 이 키를 common.php에 둘 수 있겠지만, 실서버 설정이라면 분리하는 것이 맞다. 그리고 $table_prefix 는 중요하다. 사이트마다 다른 문자열을 적용하여 다른 테이블을 사용하도록 설정하자. 물론, 의도적으로 같은 접두사를 쓰는 것도 가능하다.
자가인증서이긴 하지만 HTTPS 환경을 꾸미는데 부족함이 없다. http로 접속시 https로 리다이렉트하는 코드를 삽입하자.
<IfModule mod_rewrite.c> RewriteEngine On RewriteCond %{HTTPS} off RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301,QSA] </IfModule>
여기까지 하면 도메인마다 다른 설정 파일과 다른 테이블을 이용하되 워드프레스 코어를 하나로 쓰는 것이 가능해진다. 그러나 아직 작업이 하나 더 남아있다. 여기까지 설정하면 모든 테마와 플러그인, 그리고 업로드 디렉토리 같은 wp-content 디렉토리를 공유하기 때문이다. 이것을 도메인별로 분리하는 작업을 더해야 한다.
우선 shared/core/contents가 비어 있다. 여기에 a.shared.com, b.shared.com 두 도메인을 그대로 딴 디렉토리를 만들고, 생성된 디렉토리마다 wp-content의 index.php 파일과 plugins, themes, uploads 디렉토리를 복사해 넣는다.
그리고 shared/configs/common.php 에 아래 설정을 덧붙인다.
define( 'WP_CONTENT_DIR', "shared/contents/{$_SERVER['HTTP_HOST']}" ); define( 'WP_CONTENT_URL', "https://{$_SERVER['HTTP_HOST']}/contents/{$_SERVER['HTTP_HOST']}" );
이제 도메인마다 각자 다른 콘텐트 디렉토리를 가지게 된다.
길게 늘여쓰기는 했지만 다음이 핵심이다.
이렇게 하면 한 코어만 고정적으로 두고 새 워드프레스를 만들고 가볍게 삭제하는 것이 가능하다. 코어 업데이트도 단 한번이면 족하고, 사용 환경에 따라 장점이 많을 수 있다.
그러나 이런 세팅을 사용해 개발을 몇 번 해 봤는데 단점도 있었다. 아무리 코어가 안정적이어도 코어의 환경이 변경되면 전에 없던 에러가 발생할 우려가 있기 마련이다. 때로는 스탠드얼론으로 모든 환경을 한 벌에 두고 안정적으로 두는 것이 더 나을 수도 있다.
그리고 개발시 WP CLI를 자주 사용하게 되는데, 이 방법을 쓰는 경우 코어와 설정 등이 분리되어 있어 WP CLI를 사용하기 위해 추가적으로 파라미터를 더 지정해 줘야 하기 때문에 조금, 아니 꽤 불편하다는 단점이 있다. 이런 추가적인 설정을 계속해서 요구하기 때문에 오히려 더 번잡스러운 것이 아닌가 하는 생각도 좀 들었다. 워드프레스 코어 소스 파일이 많기는 하지만, 그렇다고 용량이 감당 못할 정도로 엄청난 것도 아니고…
이제 앞으로 새로운 도메인으로 워드프레스를 설치하려면 다음 순서대로 하면 된다.
플러그인/테마 개발시 flush_rewrite_rules()라는 함수를 심심찮게 쓴다. 안 하면 사이트에서 404 에러가 날 수 있어 항상 코드에 집어 넣는 나름 중요한 역할을 하는 녀석이다. 그런데 이 함수가 하는 역할이 정확히 무엇인지 알고 있는가? 이 포스트에서 이 함수에 대해 좀 더 정확히 알아보고 기록해본다.
(더 보기…)워드프레스 사이트 이용을 하다 보면 별 희한한 버그를 만날 때가 가끔씩 있다. 뭐, 사실 대부분은 내가 짠 프로그램에서 나는 버그지만, 가끔은 진짜 서드파티 플러그인의 버그일 때도 있고 아니면 내가 만든 플러그인이 아닌 레거시에서 의도치 않은 버그가 나올 때가 있다.
이럴 때는 모든 테마와 플러그인을 완전히 끄고 하나하나 켜 가면서 범인을 색출하는 방법이 있다. 워드프레스에는 수많은 필터와 액션이 뒤엉켜 돌아가기 때문에 문제 파악이 매우 어려울 수도 있다. 그러므로 이럴 땐 기능을 꺼보면서 시작점을 찾아 보는 것이 가장 단순명료하다.
그런데 문제가 있다. 운영 중인 사이트에 함부로 플러그인과 테마를 껐다 켤 수는 없다. 사이트의 기능이 멈출 수도 있기 때문이다. 과연 이럴 때는 어떻게 해야 할까?
(더 보기…)