웹사이트 검색

플러그인을 사용하여 WordPress에 페이지 템플릿 추가


나만의 페이지 템플릿을 만들고 싶었지만 테마 자체에 액세스할 수 없었던 적이 있나요? 나는 WordPress 플러그인 작성자로서 플러그인을 개발할 때 이 문제가 특히 짜증나는 것을 발견했습니다. 다행히도 해결책은 매우 간단합니다! PHP를 통해 직접 WordPress 페이지 템플릿을 동적으로 생성하는 데 필요한 몇 줄의 코드를 빠르게 안내하겠습니다.

이 기사에 대한 영감과 코드 솔루션 뒤에 숨은 천재는 Tom McFarlin에게서 나왔습니다. 저는 Tom McFarlin의 GitHub에서 찾을 수 있는 원본 코드의 편집된 버전을 사용하고 있습니다. 무슨 일이 일어나고 있는지 설명하는 데 매우 도움이 되었기 때문에 그의 의견을 그대로 유지했습니다(내 의견도 일부 추가했습니다). 나 자신도 이보다 더 잘 말할 수 없었습니다!

이 게시물 맨 아래에서 전체 코드와 예제 플러그인을 찾을 수 있습니다.

시작해볼까요?

코드

PHP 클래스를 사용하여 PHP 함수를 만듭니다. PHP 클래스에 대해 잘 알지 못하는 분들을 위해 설명하자면, 클래스는 함께 작동하는 함수와 변수의 모음을 포함하는 객체로 정의됩니다. 구문과 이론에 대한 자세한 내용은 PHP.net 소개를 확인하세요.

래퍼에는 3개의 변수만 필요합니다.

  1. 플러그인 슬러그: 이는 단순히 플러그인의 고유 식별자로 사용됩니다.
  2. 클래스 인스턴스: 이 클래스의 인스턴스를 WordPress의 헤드에 추가하므로 저장하는 것이 좋습니다.
  3. 템플릿 배열: 짐작할 수 있듯이 이것은 템플릿 이름과 제목을 포함하는 배열입니다.

코드는 다음과 같습니다.

class PageTemplater {

		/**
         * A Unique Identifier
         */
		 protected $plugin_slug;

        /**
         * A reference to an instance of this class.
         */
        private static $instance;

        /**
         * The array of templates that this plugin tracks.
         */
        protected $templates;

클래스 인스턴스 가져오기

이전에 말했듯이 add_filter() 함수를 사용하여 WordPress 헤더에 클래스 인스턴스를 추가할 것입니다. 따라서 이 인스턴스를 반환(또는 생성)하는 메서드가 필요합니다.

이를 위해서는 'get_instance'라는 간단한 메소드가 필요합니다. 아래에서 확인해 보세요.

/**
 * Returns an instance of this class. 
 */
public static function get_instance() {

	if( null == self::$instance ) {
		self::$instance = new PageTemplater();
	} 

	return self::$instance;

}

이것은 'add_action()'을 사용하여 WordPress 헤드에 클래스를 추가할 때 호출되는 메소드입니다.

WordPress 필터

이제 'get_instance' 메소드를 정리했습니다. 실제로 인스턴스화될 때 무슨 일이 일어나는지 정리해야 합니다.

WordPress에 내장된 add_filter() 함수를 사용하여 WordPress 초기화 타임라인을 따라 주요 지점에 클래스 인스턴스를 추가합니다. 이 방법을 사용하여 페이지가 호출될 때 템플릿으로 사용할 파일을 WordPress에 알려주고 페이지 편집기의 드롭다운 메뉴에 표시할 제목을 지정하는 등 페이지 템플릿의 데이터를 관련 슬롯에 삽입합니다.

이를 위해 '__construct' 메소드를 사용해야 합니다(클래스가 인스턴스화될 때 실행됩니다).

/**
 * Initializes the plugin by setting filters and administration functions.
 */
private function __construct() {

	$this->templates = array();

	// Add a filter to the attributes metabox to inject template into the cache.
	if ( version_compare( floatval( get_bloginfo( 'version' ) ), '4.7', '<' ) ) {

		// 4.6 and older
		add_filter(
			'page_attributes_dropdown_pages_args',
			array( $this, 'register_project_templates' )
		);

	} else {

		// Add a filter to the wp 4.7 version attributes metabox
		add_filter(
			'theme_page_templates', array( $this, 'add_new_template' )
		);

	}

	// Add a filter to the save post to inject out template into the page cache
	add_filter(
		'wp_insert_post_data', 
		array( $this, 'register_project_templates' ) 
	);

	// Add a filter to the template include to determine if the page has our 
	// template assigned and return it's path
	add_filter(
		'template_include', 
		array( $this, 'view_project_template') 
	);

	// Add your templates to this array.
	$this->templates = array(
		'goodtobebad-template.php' => 'It\'s Good to Be Bad',
	);

}

여기에는 4가지 다른 일이 진행되고 있습니다(사용할 변수를 준비하는 ' $this->templates=array();' 무시).

  1. 9~13행: 이 필터는 'page_attributes_dropdown_pages_args' 후크에 'register_project_templates'를 추가합니다. 이는 WordPress 캐시를 새로운 템플릿으로 채우고 WordPress를 속여 페이지 템플릿 파일이 실제로 템플릿 디렉터리에 존재한다고 믿게 만드는 것입니다. 그러면 페이지 편집기의 페이지 속성 메타 상자에 있는 드롭다운 목록에 페이지 템플릿이 추가됩니다.
  2. 16 – 20행: 여기서는 이전 코드 블록과 기본적으로 동일한 작업을 수행합니다. 단, 이번에는 페이지 템플릿(선택한 경우)을 저장된 게시물 데이터에도 추가한다는 점만 다릅니다.
  3. 23~28행: 이 필터는 'view_project_template' 후크에 'template_include'를 추가합니다. 이것은 매우 중요한 기능입니다. 이는 페이지 템플릿 파일이 실제로 어디에 있는지 WordPress에 알려줍니다. WordPress에서는 제공된 경로를 사용하여 최종 페이지를 렌더링합니다.
  4. 31~34행: 간단하지만 매우 중요합니다. 여기에서 추가하려는 페이지 템플릿과 페이지 템플릿 파일이 있는 파일에 대한 상대 경로(예: 'something.php')를 지정합니다. 하나의 예를 포함했습니다(예제 플러그인에서 사용됩니다). 일반적인 예는 아래에서 확인하세요.
$this->templates = array(
	'FILE_PATH_AND_NAME'               => 'TEMPLATE_TITLE',
	'awesome-template.php'             => 'Awesome',
	'templates/organised-template.php' => 'Organised',
);

(먹고, 자고,) 코딩하고, 필요에 따라 반복하세요.

등록_프로젝트_템플릿()

나는 이전에 이 방법을 언급한 적이 있습니다. 실제로 무엇을 하는지 봅시다.

기본적으로 이 방법의 목적은 WordPress의 캐시를 조작하여 페이지 템플릿에 대한 관련 데이터를 올바른 위치에 삽입하는 것입니다. 먼저 코드를 살펴보고 나중에 자세히 설명하겠습니다.

public function register_project_templates( $atts ) {

	// Create the key used for the themes cache
	$cache_key = 'page_templates-' . md5( get_theme_root() . '/' . get_stylesheet() );

	// Retrieve the cache list. 
	// If it doesn't exist, or it's empty prepare an array
	$templates = wp_get_theme()->get_page_templates();
	if ( empty( $templates ) ) {
		$templates = array();
	} 

	// New cache, therefore remove the old one
	wp_cache_delete( $cache_key , 'themes');

	// Now add our template to the list of templates by merging our templates
	// with the existing templates array from the cache.
	$templates = array_merge( $templates, $this->templates );

	// Add the modified cache to allow WordPress to pick it up for listing
	// available templates
	wp_cache_add( $cache_key, $templates, 'themes', 1800 );

	return $atts;

}

바로 그때. 4호선이 가장 먼저 눈에 띄는 곳이다. 짐작하셨겠지만 우리는 '캐시 키'를 생성하고 있습니다. 이는 Google 페이지 템플릿 데이터의 고유 식별자로 사용됩니다. md5() 함수를 사용하면 충돌을 피하기 위해 고유한 문자열 식별자가 생성됩니다.

다음으로 8행에서는 페이지 템플릿 캐시(이미 존재하는 경우)를 검색하고 가져옵니다. 그러면 경로와 제목의 배열이 반환됩니다. 9-11행에서는 캐시 쿼리의 출력이 있는지 확인합니다. 그렇다면 좋습니다. 그렇지 않은 경우 캐시에 병합할 데이터를 보관할 로컬 배열을 만듭니다.

다음 단계가 중요합니다. 14행에서는 기존 페이지 템플릿 캐시를 삭제합니다. 걱정하지 마세요. 데이터는 손실되지 않습니다. $templates 변수에 저장됩니다.

18행에서는 기존 페이지 템플릿 캐시를 새 항목과 병합하고 22행에서는 전체 페이지 템플릿 캐시를 WordPress 시스템에 다시 삽입합니다.

단순한!

view_project_template()

이제 마지막 방법을 사용하고 있습니다. 여기가 실제 페이지 템플릿 파일이 어디에 있는지 WordPress에 알려주는 곳입니다.

/**
 * Checks if the template is assigned to the page
 */
public function view_project_template( $template ) {
	
	// Get global post
	global $post;

	// Return template if post is empty
	if ( ! $post ) {
		return $template;
	}

	// Return default template if we don't have a custom one defined
	if ( !isset( $this->templates[get_post_meta( 
		$post->ID, '_wp_page_template', true 
	)] ) ) {
		return $template;
	} 

	$file = plugin_dir_path(__FILE__). get_post_meta( 
		$post->ID, '_wp_page_template', true
	);

	// Just to be safe, we check if the file exist first
	if ( file_exists( $file ) ) {
		return $file;
	} else {
		echo $file;
	}

	// Return template
	return $template;

}

그렇다면 이 방법은 전역 $post 변수(6행)를 확인하게 됩니다. 게시물에 대해 페이지 템플릿('_wp_page_template')이 설정되었는지 확인합니다(페이지여야 함을 의미). 그렇지 않다면 걱정하지 마세요. 페이지가 아닌 페이지에는 페이지 템플릿이 있을 수 없습니다.

16행에서는 페이지 템플릿 파일의 위치를 지정합니다. 위에서 설정한 대로 플러그인의 루트 디렉터리에 지정된 페이지 템플릿 파일이 있는지 확인합니다. (이것은 쉽게 변경할 수 있습니다. 아래를 참조하십시오.)

// Just changing the page template path
// WordPress will now look for page templates in the subfolder 'templates',
// instead of the root
$file = plugin_dir_path(__FILE__). 'templates/' .get_post_meta( 
	$post->ID, '_wp_page_template', true 
);

그런 다음 21~24행에서 파일이 실제로 존재하는지 확인하는 약간의 유효성 검사를 수행합니다. 그렇다면 굉장합니다! 그렇지 않다면, 이런… WordPress가 템플릿 파일을 찾을 수 없거나 빈 화면이 나타날 경우 PHP 오류 메시지가 나타날 가능성이 높습니다. 이러한 증상 중 하나라도 익숙하게 들리면 $file 변수를 화면에 인쇄하여 템플릿 파일 경로를 확인하세요.

이 코드를 상업적으로 사용할 계획이라면(내 코드 버전에는 라이선스가 없으므로 원하는 대로 자유롭게 사용할 수 있습니다.) 최대한 많은 시간을 오류 처리에 투자하는 것이 좋습니다. 신뢰할 수 있음.

그게 그거야. 수업이 완료되면 해야 할 일은 단 하나뿐입니다. 이를 WordPress 헤드에 추가하는 것입니다.

add_action( 'plugins_loaded', array( 'PageTemplater', 'get_instance' ) );

끝까지 완수하셨다면 축하드립니다! 제가 말씀드린 내용이 도움이 되셨기를 바라며, 앞으로도 혜택을 누리시기 바랍니다!

전체 코드

다음은 쉬운 복사 및 붙여넣기를 위한 플러그인의 전체 코드입니다.

<?php
/*
Plugin Name: Page Template Plugin : 'Good To Be Bad'
Plugin URI: http://www.wpexplorer.com/wordpress-page-templates-plugin/
Version: 1.1.0
Author: WPExplorer
Author URI: http://www.wpexplorer.com/
*/

class PageTemplater {

	/**
	 * A reference to an instance of this class.
	 */
	private static $instance;

	/**
	 * The array of templates that this plugin tracks.
	 */
	protected $templates;

	/**
	 * Returns an instance of this class. 
	 */
	public static function get_instance() {

		if ( null == self::$instance ) {
			self::$instance = new PageTemplater();
		} 

		return self::$instance;

	} 

	/**
	 * Initializes the plugin by setting filters and administration functions.
	 */
	private function __construct() {

		$this->templates = array();


		// Add a filter to the attributes metabox to inject template into the cache.
		if ( version_compare( floatval( get_bloginfo( 'version' ) ), '4.7', '<' ) ) {

			// 4.6 and older
			add_filter(
				'page_attributes_dropdown_pages_args',
				array( $this, 'register_project_templates' )
			);

		} else {

			// Add a filter to the wp 4.7 version attributes metabox
			add_filter(
				'theme_page_templates', array( $this, 'add_new_template' )
			);

		}

		// Add a filter to the save post to inject out template into the page cache
		add_filter(
			'wp_insert_post_data', 
			array( $this, 'register_project_templates' ) 
		);


		// Add a filter to the template include to determine if the page has our 
		// template assigned and return it's path
		add_filter(
			'template_include', 
			array( $this, 'view_project_template') 
		);


		// Add your templates to this array.
		$this->templates = array(
			'goodtobebad-template.php' => 'It\'s Good to Be Bad',
		);
			
	} 

	/**
	 * Adds our template to the page dropdown for v4.7+
	 *
	 */
	public function add_new_template( $posts_templates ) {
		$posts_templates = array_merge( $posts_templates, $this->templates );
		return $posts_templates;
	}

	/**
	 * Adds our template to the pages cache in order to trick WordPress
	 * into thinking the template file exists where it doens't really exist.
	 */
	public function register_project_templates( $atts ) {

		// Create the key used for the themes cache
		$cache_key = 'page_templates-' . md5( get_theme_root() . '/' . get_stylesheet() );

		// Retrieve the cache list. 
		// If it doesn't exist, or it's empty prepare an array
		$templates = wp_get_theme()->get_page_templates();
		if ( empty( $templates ) ) {
			$templates = array();
		} 

		// New cache, therefore remove the old one
		wp_cache_delete( $cache_key , 'themes');

		// Now add our template to the list of templates by merging our templates
		// with the existing templates array from the cache.
		$templates = array_merge( $templates, $this->templates );

		// Add the modified cache to allow WordPress to pick it up for listing
		// available templates
		wp_cache_add( $cache_key, $templates, 'themes', 1800 );

		return $atts;

	} 

	/**
	 * Checks if the template is assigned to the page
	 */
	public function view_project_template( $template ) {
		
		// Get global post
		global $post;

		// Return template if post is empty
		if ( ! $post ) {
			return $template;
		}

		// Return default template if we don't have a custom one defined
		if ( ! isset( $this->templates[get_post_meta( 
			$post->ID, '_wp_page_template', true 
		)] ) ) {
			return $template;
		} 

		$file = plugin_dir_path( __FILE__ ). get_post_meta( 
			$post->ID, '_wp_page_template', true
		);

		// Just to be safe, we check if the file exist first
		if ( file_exists( $file ) ) {
			return $file;
		} else {
			echo $file;
		}

		// Return template
		return $template;

	}

} 
add_action( 'plugins_loaded', array( 'PageTemplater', 'get_instance' ) );

플러그인

Github에서 전체 코드를 플러그인으로 다운로드할 수도 있습니다.

포스트 에디터 클로즈업

다음은 작동 중인 플러그인의 클로즈업입니다. 페이지 속성 아래에 추가된 페이지 템플릿이 보이나요?