ウェブサイト検索

プラグインを使用してページテンプレートをWordPressに追加する


独自のページ テンプレートを作成したいと思ったことはありますが、テーマ自体にアクセスできなかったことがありますか? WordPress プラグインの作成者である私は、プラグインを開発するときにこの問題が特に厄介であると感じています。ありがたいことに、解決策は非常に簡単です。 PHP を通じて直接 WordPress ページ テンプレートを動的に作成するために必要な数行のコードを簡単に説明します。

この記事とコード ソリューションの背後にある天才のインスピレーションは Tom McFarlin から来ています。私は彼のオリジナル コードを編集したバージョンを使用しています。これは彼の GitHub で見つけることができます。何が起こっているのかを説明するのに非常に役立つと思うので、私は彼のコメントをそのまま残しておきます(そして私自身のコメントもいくつか追加しました)。私自身ではこれ以上うまく言えませんでした。

コード全体とプラグインの例はこの投稿の一番下にあります。

はじめましょう?

コード

PHP クラスを使用して PHP 関数を作成します。 PHP クラスに詳しくない方のために説明すると、クラスは、連携して動作する関数と変数のコレクションを含むオブジェクトとして定義されます。構文と理論の詳細については、PHP.net の概要を確認してください。

私たちのラッパーに必要な変数は 3 つだけです。

  1. プラグイン スラグ: これは単にプラグインの一意の識別子として使用されます。
  2. クラス インスタンス: このクラスのインスタンスを WordPress の head に追加するので、それを保存したほうがよいでしょう。
  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: このフィルタは、「register_project_templates」を「page_attributes_dropdown_pages_args」フックに追加しています。これにより、WordPress キャッシュに新しいテンプレートが追加され、WordPress がページ テンプレート ファイルが実際にテンプレート ディレクトリに存在すると信じ込ませます。これにより、ページ エディターのページ属性メタ ボックスのドロップダウン リストにページ テンプレートが追加されます。
  2. 行 16 ~ 20: ここでは、前のコード ブロックと基本的に同じことを行っていますが、今回はページ テンプレート (選択されている場合) を保存された投稿データにも追加している点が異なります。
  3. 行 23 ~ 28: このフィルターは、「template_include」を「view_project_template」フックに追加しています。これは非常に重要な機能です。これにより、ページ テンプレート ファイルが実際にどこにあるかが WordPress に通知されます。 WordPress は、これによって提供されるパスを使用して、最終ページをレンダリングします。
  4. 31 ~ 34 行目: これは単純ですが、非常に重要です。ここで、追加するページ テンプレートと、 ページ テンプレート ファイルが存在するファイルへの相対パスを指定します (例: ‘something.php’ )。例を 1 つ含めました (プラグインの例で使用します)。一般的な例については、以下を確認してください。
$this->templates = array(
	'FILE_PATH_AND_NAME'               => 'TEMPLATE_TITLE',
	'awesome-template.php'             => 'Awesome',
	'templates/organised-template.php' => 'Organised',
);

(食べる、寝る、) コードを書き、必要に応じて繰り返します。

register_project_templates()

この方法については以前にも触れました。実際に何をするのか見てみましょう。

基本的に、このメソッドの目的は、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 行目です。ご想像のとおり、「キャッシュ キー」を生成しています。これは当社のページ テンプレート データの一意の識別子として使用されます。 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 で完全なコードをプラグインとしてダウンロードすることもできます。

ポストエディターのクローズアップ

ここでは、実際に動作しているプラグインの拡大図を示します。ページ属性の下にページ テンプレートが追加されていますか?