2026年9月24日
2026年9月24日
WordPressのテーマテンプレートエラーを解決する方法
はじめに
WordPressでカスタム投稿タイプの単一記事ページにsingle-{post_type}.phpを作成したのに読み込まれない・固定ページに特定のテンプレートを割り当てたはずなのに反映されない・get_template_part()で読み込もうとしたファイルが見つからない・子テーマに追加したテンプレートファイルが親テーマのものに上書きされてしまうといった問題は、WordPressのテンプレート階層と読み込みルールを理解することで解決できます。
症状・原因
- テンプレートファイルの命名規則が間違っており、WordPressのテンプレート階層に一致していない
- 子テーマと親テーマの両方に同名テンプレートがあり、期待と逆の優先順位で読み込まれている
get_template_part()のスラッグ・名前引数のパスが正しくなく、ファイルが見つからない- ページテンプレートのPHPファイルヘッダーコメントの
Template Name:が記述されていない
解決手順
ステップ1:テンプレート読み込みをデバッグする
# 現在使用しているテンプレートを確認
wp eval "
add_filter('template_include', function(\$template) {
error_log('Template: ' . \$template);
return \$template;
});
"
# テンプレート階層を確認(WP_DEBUG 時)
wp eval "
add_filter('template_include', function(\$template) {
echo basename(\$template);
return \$template;
}, 999);
"
# テンプレートの探索順を確認
wp eval "
// 例:カスタム投稿タイプ 'product' の単一記事
\$templates = [
'single-product-{slug}.php',
'single-product.php',
'single.php',
'singular.php',
'index.php',
];
foreach (\$templates as \$tpl) {
\$path = locate_template(\$tpl);
echo \$tpl . ': ' . (\$path ? '✓ ' . \$path : '× なし') . PHP_EOL;
}
"
# 固定ページのテンプレートを確認
wp eval "
\$page_id = 5;
echo get_page_template_slug(\$page_id) ?: 'デフォルトテンプレート';
"
ステップ2:テンプレート階層を正しく理解する
WordPressのテンプレート階層(優先度順)
■ 単一投稿 (single post):
single-{post_type}-{slug}.php
single-{post_type}.php
single.php → singular.php → index.php
■ 固定ページ (page):
{custom-template}.php ← ページ属性で指定
page-{slug}.php
page-{id}.php
page.php → singular.php → index.php
■ カスタム投稿タイプアーカイブ:
archive-{post_type}.php
archive.php → index.php
■ カテゴリーアーカイブ:
category-{slug}.php
category-{id}.php
category.php → archive.php → index.php
■ 検索結果: search.php → index.php
■ 404: 404.php → index.php
■ フロントページ: front-page.php → home.php → index.php
// ✅ テンプレートフィルターで動的にテンプレートを変更
add_filter('single_template', function(string $template): string {
if (get_post_type() === 'product') {
$custom = get_stylesheet_directory() . '/templates/single-product.php';
if (file_exists($custom)) {
return $custom;
}
}
return $template;
});
// ✅ ページテンプレートをプラグインから登録する
add_filter('theme_page_templates', function(array $templates): array {
$templates['templates/my-landing-page.php'] = 'ランディングページ';
return $templates;
});
// ✅ template_include でリクエストに応じてテンプレートを完全に差し替え
add_filter('template_include', function(string $template): string {
// 特定のクエリ変数に応じてテンプレートを変更
if (get_query_var('my_custom_page') === 'dashboard') {
$custom = get_stylesheet_directory() . '/templates/dashboard.php';
if (file_exists($custom)) {
return $custom;
}
}
return $template;
});
ステップ3:get_template_partを正しく使う
// ✅ get_template_part の正しい使い方
// ファイル: {theme}/template-parts/content/post.php
// WP 5.5 以降の書き方($args で変数を渡せる)
get_template_part('template-parts/content', 'post', [
'post_id' => get_the_ID(),
'show_excerpt' => true,
'image_size' => 'medium',
]);
// テンプレートパーツファイル内での引数の受け取り方:
// template-parts/content/post.php:
$args = wp_parse_args($args, [
'post_id' => 0,
'show_excerpt' => false,
'image_size' => 'thumbnail',
]);
$post_id = absint($args['post_id']);
$show_excerpt = (bool) $args['show_excerpt'];
// ✅ locate_template でファイルの存在を確認してから読み込む
$template = locate_template([
'template-parts/card-' . get_post_type() . '.php',
'template-parts/card.php',
]);
if ($template) {
load_template($template, false, ['post_id' => get_the_ID()]);
}
// ✅ プラグインからテンプレートを提供する(テーマで上書き可能)
function my_plugin_get_template(string $template_name, array $args = []): void {
// 1. 子テーマで上書き可能
$theme_file = locate_template('my-plugin/' . $template_name);
if ($theme_file) {
load_template($theme_file, false, $args);
return;
}
// 2. プラグインのデフォルトテンプレート
$plugin_file = MY_PLUGIN_DIR . 'templates/' . $template_name;
if (file_exists($plugin_file)) {
load_template($plugin_file, false, $args);
}
}
ステップ4:ページテンプレートを正しく作成する
<?php
/**
* Template Name: ランディングページ
* Template Post Type: page, post
*
* ↑ このコメントが必須。Template Name が表示名になる
*/
// ✅ 直接アクセスを禁止
if (!defined('ABSPATH')) {
exit;
}
get_header();
?>
<main id="main" class="site-main lp-main">
<?php while (have_posts()) : the_post(); ?>
<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
<div class="entry-content">
<?php the_content(); ?>
</div>
</article>
<?php endwhile; ?>
</main>
<?php
// ✅ フッターは必ず get_footer() で(wp_footer() が実行される)
get_footer();
ステップ5:テンプレートのデバッグと最適化
// ✅ 現在のテンプレートファイルを管理バーに表示
add_action('wp_before_admin_bar_render', function(): void {
if (!current_user_can('manage_options') || !is_admin_bar_showing()) {
return;
}
global $wp_admin_bar, $template;
$wp_admin_bar->add_node([
'id' => 'current-template',
'title' => '📄 ' . basename($template ?? ''),
'href' => false,
]);
});
// ✅ template_redirect でリダイレクト
add_action('template_redirect', function(): void {
// 非公開投稿へのアクセスをリダイレクト
if (is_singular() && !current_user_can('read_post', get_the_ID())) {
wp_redirect(home_url('/'));
exit;
}
// カスタムクエリ変数によるページ切り替え
if (get_query_var('my_page') === 'thankyou') {
include get_stylesheet_directory() . '/templates/thankyou.php';
exit;
}
});
// ✅ テンプレートのコンテキストを確認するデバッグ関数
function my_debug_template_context(): void {
if (!current_user_can('manage_options')) {
return;
}
$context = [
'is_front_page' => is_front_page(),
'is_home' => is_home(),
'is_singular' => is_singular(),
'is_archive' => is_archive(),
'post_type' => get_post_type(),
'queried_object'=> get_class(get_queried_object()),
];
echo '<!-- Template context: ' . wp_json_encode($context) . ' -->';
}
注意事項
- ページテンプレートとして使うPHPファイルには必ずファイル先頭に
/ Template Name: テンプレート名 /コメントを記述してください。このコメントがないとWordPressはそのファイルをページテンプレートとして認識せず、管理画面の「テンプレート」ドロップダウンに表示されません get_template_part()はWP 5.5以降で第3引数($args)を使えますが、それ以前のバージョンとの互換性が必要な場合はset_query_var()とget_query_var()でデータを渡してください
まとめ
WordPressのテーマテンプレートエラーの解決は①template_includeフィルターで現在のテンプレートをログ・locate_template()で探索確認、②テンプレート階層の優先順位を理解(single-{type}-{slug}.php → single-{type}.php → single.php)・single_templateフィルターでプログラムから変更、③get_template_part(slug, name, $args)で変数を渡す・locate_template()+load_template()で条件付き読み込み・プラグインテンプレートはテーマで上書き可能に設計、④ページテンプレートはTemplate Name: 名前コメントが必須・template_post_typeで対応投稿タイプを制限、⑤管理バーにテンプレート名を表示・template_redirectでリダイレクトや差し替えの手順で解決します。