← home

워드프레스 – 예쁘지 않은 Pretty URL

Pretty URL은 Clean URL, Restful URL, User-friendly URL, SEO-friendly URL 이라고도 합니다. 쿼리스트링을 포함한 URL은 의미와 구조를 이해하기 힘든 반면, Pretty URL은 대략의 구조와 의미를 URL만으로도 알 수 있어서, 이미 많은 웹사이트들이 이를 적용하고 있습니다. 자세한 내용은 여기를 참조.

Ugly URL Pretty URL
http://example.com?p=1&page=2 http://example.com/hello-world/page/2

Pretty URL을 보면 ‘Hello World’라는 포스트의 두번째 페이지임을 쉽게 알 수 있습니다.

Screen Shot 2014-05-07 at 10.12.54 PM워드프레스에서는 설정 → 고유주소 페이지에서 너무나 쉽게 URL 구조를 만들 수 있습니다.

그런데 워드프레스를 이용하여 웹사이트를 만들다보면, 한글 문자열과 관련하여 다소 신경쓰이는 것들이 있는데, 그 중 하나가 바로 Pretty URL 사용시 인코딩된 한글 URL의 문제입니다.

만약 고유주소 설정을 ‘/%postname%/’으로 설정하는 경우, 아래와 같이 깔끔한 주소가 만들어지겠지만,
http://example.com/sample-post/

글 제목이 한글인 경우 아래와 같이 길이도 길어지거니와 일반인들 눈에는 깨진… 혹은 의심스러운 주소로 보일 수 있습니다.
http://example.com/%EC%83%98%ED%94%8C-%ED%8F%AC%EC%8A%A4%ED%8A%B8/

워드프레스가 제공하는 짧은링크(shortlink) 또는 단축URL 플러그인을 이용하여 문서 어딘가에 그 URL을 노출해둘 수도 있겠지만, 사람들은 보통 주소창의 주소를 카피하여 공유하곤 하기에 한글로 인코딩된 긴 주소는 그냥 넘어갈 수 없는 문제입니다.

그래서 저는 보통 고유주소를 ‘/%post_id%/’로 설정합니다. 이렇게 하면 글(post) 타입은 아래와 같은 구조가 됩니다.
http://example.com/7/

비록 모양만 Pretty하지만, 적어도 괴상해보이지는 않습니다. 단, 고유주소 설정은 글(post) 타입에만 해당됩니다. 페이지(page) 타입은 아래와 같이 여전히 ‘/%postname%/’ 형식이 유지되는데요, 이는 오히려 다행인 듯 합니다. 페이지는 주로 정적인 콘텐츠를 노출하는데 사용되므로, 페이지 생성시 조금만 신경써주면 될테니까요.
http://example.com/about/

하지만 문제는 사용자정의 포스트 타입입니다. 다음과 같이 ‘book’이라는 사용자정의 포스트타입을 추가해봅시다.

add_action( 'init', 'register_book_post_type' );
function register_book_post_type(){
	$args = array(
		'label' => '책',
		'public' => true,
	);
	register_post_type( 'book', $args );
}

그리고 ‘이상한 나라의 앨리스’라는 제목으로 포스트 하나를 생성해보았는데요, 아래와 같이 주소가 많이 길어집니다.
http://example.com/book/%EC%9D%B4%EC%83%81%ED%95%9C-%EB%82%98%EB%9D%BC%EC%9D%98-%EC%95%A8%EB%A6%AC%EC%8A%A4/

글(post) 타입처럼 책(book) 타입도 포스트네임 대신 포스트아이디로 URL을 만드는 방법은 그리 복잡하지 않습니다. 다만 이를 이해하는 것이 처음에는 좀 어려울 수 있습니다. 포스트 타입 등록시 어떻게 재작성 룰과 구조가 추가되는지(wp-includes/post.php의 register_post_type 함수)와 포스트 고유주소를 어떻게 뽑아내는지(register_post_type/link-template.php의 get_post_permalink 함수)를 잘 살펴본다면 아마도 아래 코드를 이해하는데 도움이 될 듯 합니다.

add_action( 'init', 'register_book_post_type' );
function register_book_post_type(){
	$args = array(
		'label' => '책',
		'public' => true,
	);
	$args = register_post_type( 'book', $args );
	if ( false !== $args->rewrite && ( is_admin() || '' != get_option( 'permalink_structure' ) ) ) {
		add_rewrite_tag( '%book_id%', '([0-9]{1,})', 'post_type=book&p=' );
		add_rewrite_rule( 'book/([0-9]{1,})/([0-9]{1,})/?$', 'index.php?post_type=book&p=$matches[1]&page=$matches[2]', 'top' );
		add_permastruct( 'book', 'book/%book_id%', $args->rewrite );
	}
}

라인 8. 재작성을 허용하는 포스트타입인지, 워드프레스가 고유주소를 사용하는지 체크
라인 9-11. add_rewrite_tag, add_rewrite_rule, add_permastruct는 워드프레스의 Rewrite API 함수들입니다. 워드프레스 Rewrite API를 제대로 이해하기 위해서는 정규식 등 미리 학습해야하는 내용이 너무 많고 난이도 역시 높은 편입니다. 이 부분은 나중에 자세히 다루어보도록 하겠습니다.
라인 9. 워드프레스가 사용자정의 쿼리스트링 변수(book_id)를 인식할 수 있도록 합니다. 포스트의 고유주소를 가져오는 과정에서 ‘%book_id%’를 포스트 아이디로 대체해줄 것입니다.
라인 10. 페이징을 위한 새로운 룰 추가.
라인 11. 새로운 고유주소 구조를 추가합니다.

현재 상태에서 포스트의 고유주소는 아래와 같이 만들어 질 것입니다.
http://example.com/book/%book_id%/

이제 포스트의 고유주소(permalink)를 가져오는 함수(get_post_permalink)의 ‘post_type_link’ 필터 훅을 이용하여 ‘%book_id%’를 포스트 아이디로 대체해줍니다.

add_filter( 'post_type_link', 'book_post_type_link', 10, 2);
function book_post_type_link($post_link, $post) {
	global $wp_rewrite;
	if ( is_wp_error( $post ) )
		return $post;
	if( 'book' == get_post_type($post) && $post_link = $wp_rewrite->get_extra_permastruct('book') ){
		$post_link = str_replace('%book_id%', $post->ID, $post_link);
		$post_link = home_url( user_trailingslashit($post_link) );
	}
	return $post_link;
}

이제 ‘책’ 포스트 타입의 고유주소는 아래와 같이 만들어 질 것입니다.
http://example.com/book/423/

여기서 잊지 말아야할 점은, 포스트 타입을 새로 추가하거나 고유주소 구조를 변경하는 경우 재작성 룰을 다시 만들어주어야 한다는 점입니다. 그렇지않으면 404페이지가 뜰거예요.
모든 포스트타입이 등록된 후에 flush_rewrite_rules 함수를 한번만 실행해주거나, 보다 간단한 방법은.. 설정 → 고유주소 페이지에서 ‘변경 사항 저장’ 버튼을 한번 클릭해주는 것.

add_action( 'init', 'register_book_post_type' );

function register_book_post_type(){
	$args = array(
		'label' => '책',
		'public' => true,
	);
	
	$args = register_post_type( 'book', $args );
	
	if ( false !== $args->rewrite && ( is_admin() || '' != get_option( 'permalink_structure' ) ) ) {
		add_rewrite_tag( '%book_id%', '([0-9]{1,})', 'post_type=book&p=' );
		add_rewrite_rule( 'book/([0-9]{1,})/([0-9]{1,})/?$', 'index.php?post_type=book&p=$matches[1]&page=$matches[2]', 'top' );
		add_permastruct( 'book', 'book/%book_id%', $args->rewrite );
	}
}

add_filter( 'post_type_link', 'book_post_type_link', 10, 2);

function book_post_type_link($post_link, $post) {
	global $wp_rewrite;
	
	if ( is_wp_error( $post ) )
		return $post;
		
	if( 'book' == get_post_type($post) && $post_link = $wp_rewrite->get_extra_permastruct('book') ){
		$post_link = str_replace('%book_id%', $post->ID, $post_link);
		$post_link = home_url( user_trailingslashit($post_link) );
	}
	
	return $post_link;
}
← home