WordPress Logo WordPress title タグの出力

WordPress4.4 以降でタイトルタグを出力する仕組みや方法についての解説です。

更新日:2022年03月13日

作成日:2019年02月08日

title タグ(title 要素)

ページのタイトルは、 head 要素内の title タグ(<title>~</title>)を使って記述します。

WordPress の場合、従来はタイトルの出力は header.php 等のテンプレートの <head> タグ内で wp_title() を使って以下のような記述をしていました。

<title><?php bloginfo('name'); wp_title('|', true, 'left'); ?></title>

上記のように記述すると、以下のような HTML が出力されます。

<title>サイト名|記事のタイトル</title>

WordPress4.1 からタイトルタグは <head> タグ内に記述しなくても、functions.php に以下を記述すれば、WordPress がページ種類に応じてタイトルタグを自動的に表示(挿入)してくれるようになりました。

以下を使用する場合は <title> タグは記述しません(記述すると二重に出力されてしまいます)。

add_theme_support( 'title-tag' );

アクションフックを使わなくても問題なく動作しますが、アクションフックを使って記述する場合は、after_setup_theme フックを使います(Title Tags in 4.1)。

function setup_my_theme() {
   add_theme_support( 'title-tag' );
}
add_action( 'after_setup_theme', 'setup_my_theme');

wp_title() は WordPress4.4 で非推奨になる予定でしたが、まだ現時点(2019年2月)では非推奨になっていないようです。(関連ページ:Document title in 4.4

但し、現在は add_theme_support(); を使ってタイトルタグを出力することが推奨されています。

add_theme_support( 'title-tag' )

add_theme_support() と言う関数の引数に 'title-tag' を指定することで <title> タグが自動的に <head> タグ内に挿入されます。

add_theme_support() は WordPress の特定の機能をテーマで有効にする関数です。

//functions.php
add_theme_support( 'title-tag' );

日本語 Codex:タイトルタグ

仕組みとしては以下のようになっています。

wp-includes/default-filters.php に記述されているデフォルトのアクションの1つに以下があります。

これにより、wp_head() が実行される際に wp_head アクションの1つ _wp_render_title_tag によりタイトルタグが出力されます。

add_action( 'wp_head', '_wp_render_title_tag', 1 );

以下は wp-includes/general-template.php に記述されている _wp_render_title_tag() の定義です。

//wp-includes/general-template.php より抜粋
/**
  * Displays title tag with content.
  *
  * @ignore
  * @since 4.1.0
  * @since 4.4.0 Improved title output replaced `wp_title()`.
  * @access private
  */
function _wp_render_title_tag() {
  if ( ! current_theme_supports( 'title-tag' ) ) {
    return;
  }

  echo '<title>' . wp_get_document_title() . '</title>' . "\n";
}

current_theme_supports() でテーマ・サポートの 'title-tag' が現在有効になっているかを確認し、有効になっている場合は、wp_get_document_title() を使ってタイトルを出力しています。

この関数は、wp_head() により実行されるので、結果として <head> タグ内に挿入されることになります。

title タグのカスタマイズ

add_theme_support( 'title-tag' ) を functions.php に記述することで wp_get_document_title() によりページの種類に応じて <title> タグが <head> 内に自動的に出力されます(前述)。

また、WordPress のデフォルトの出力を変更するには、フィルターフックを使用します。

そのため、出力される <title> タグの内容をカスタマイズするには、wp_get_document_title() に設定されているフィルターを利用します。

wp_get_document_title() のソースを見ると、以下の3つのフィルターが設置されています。

  • pre_get_document_title
  • document_title_separator
  • document_title_parts

pre_get_document_title の適用時はタイトル文字列は空文字「""」ですが、document_title_parts の適用時にはタイトル文字列はパーツに分割され配列になっています。

詳細は wp_get_document_title() のソースを確認する必要があります。

pre_get_document_title

最初に設置されているフィルターが以下の pre_get_document_title です。

このフィルターを使って空文字「""」以外を返すとその文字列がタイトルとして返され、その後の処理(タイトル文字列の加工)は行われません。

/**
 * Filters the document title before it is generated.
 * Passing a non-empty value will short-circuit wp_get_document_title(),returning that value instead.
 * @since 4.4.0
 * @param string $title The document title. Default empty string.
 */
$title = apply_filters( 'pre_get_document_title', '' );
if ( ! empty( $title ) ) {
  return $title;
}

各ページのタイトル文字列を独自に設定する(書き換える)場合などに利用できます。

タイトル文字自体を書き換える例

apply_filters() の第一引数は「フィルターフック名」で、第二引数は「変更できる値」です。この例の場合、フィルターフック名は「pre_get_document_title」、変更できる値は「''」になります。

フィルターを利用するには、add_filter() の第一引数に「フィルターフック名」を、第二引数に値を変更する「フィルター関数」を指定して登録します。

以下の例の場合、引数に文字列 $title を引き取り、タイトルに表示する文字列を返すフィルター関数を作成して pre_get_document_title フィルターに登録します。

タイトルはそれぞれのページで固有にする必要があるため、場合によってはテンプレートを判定する条件分岐タグを使って個々のページで値が異なるように記述するなどの工夫が必要かもしれません(wp_get_document_title() のソースを利用すると効率的かも知れません)。

functions.php
function change_title_tag( $title ) {
  
  //条件分岐タグ等を使ってページにより $title を変更する処理
  if ( is_404() ) {
    $title = 'XXXXX';
  }elseif ( is_search() )  {
    ...
  }
  
  return $title;
}
add_filter( 'pre_get_document_title', 'change_title_tag' );

カスタムフィールドの値をタイトルとして出力(1)

以下は個別ページでカスタムフィールドにタイトルを設定している場合は、その値(文字列)をタイトルとして表示し、そうでない場合はデフォルトのシステムが生成するタイトルを表示する例です。

この例の場合、カスタムフィールドの名前(キー)は my_title_tag として、値にタイトルに表示する文字列を設定します。

カスタムフィールドの値は get_post_meta() を使って第3パラメータに true を指定して文字列として取得しています。

get_post_meta() は、もし値がない場合は空の文字列を返します。そのためカスタムフィールドに値が設定されていない場合でも、この場合は問題になりません(pre_get_document_title では空文字列以外を返した場合のみその文字列がタイトルとして返されるため)。

functions.php
function change_title_tag_with_cfv( $title ) {
  //個別ページの場合
  if ( is_singular() ) {
    //カスタムフィールドの値を取得
    $cf_title_tag = get_post_meta( get_the_ID(), 'my_title_tag', true );
    $title = esc_html( $cf_title_tag );
  }
  
  return $title;
}
add_filter( 'pre_get_document_title', 'change_title_tag_with_cfv' );

関連ページ:独自のメタボックスを表示してカスタムフィールドの値を title タグに出力

関連項目:カスタムフィールドの値をタイトルとして出力(2)

document_title_separator

2番目に設置されているフィルターが以下の document_title_separator です。

このフィルターは WordPress がページ種類によって設定したタイトル文字列内の区切り文字を変更する場合に使用します。

  /**
 * Filters the separator for the document title.
 * @since 4.4.0
 * @param string $sep Document title separator. Default '-'.
 */
$sep = apply_filters( 'document_title_separator', '-' );
タイトル文字内のセパレーターを変更

タイトル文字内のデフォルトの区切り文字(セパレータ)は「-」ですが、これを「 | 」に変更するには、以下のようにします。

引数にセパレータの文字列 $sep を取り、セパレータの文字列を変更して返す関数を作成して document_title_separator に登録します。

functions.php
function change_title_separator( $sep ){
  $sep = ' | ';
  return $sep;
}
add_filter( 'document_title_separator', 'change_title_separator' );

document_title_parts

最後に設置されているフィルターが以下の document_title_parts です。

このフィルターは WordPress がページ種類によって設定したタイトル文字列のパーツを変更する場合に使用します。

/**
 * Filters the parts of the document title.
 * @since 4.4.0
 * @param array $title {
 *     The document title parts.
 *     @type string $title   Title of the viewed page.
 *     @type string $page    Optional. Page number if paginated.
 *     @type string $tagline Optional. Site description when on home page.
 *     @type string $site    Optional. Site title when not on home page.
 * }
 */
$title = apply_filters( 'document_title_parts', $title );
タイトルをパーツごとに変更

この apply_filters() が実行される時点では $title は配列になっていて以下のパーツに分割されています。

パーツ(要素) 内容
$title['title'] メインのタイトル文字列
$title['page'] ページが分割されている場合のページ番号
$title['tagline'] フロントページの場合のキャッチフレーズ
$title['site'] フロントページでない場合に表示するサイト名

このフィルターの実行後、配列 $title はページ種類により上記のパーツに区切り文字を付けた文字列に変換され、エスケープ処理等を経て呼び出し元に返されます。

もし、以下のように記述するとフロントページのタイトルは「サイト名 - キャッチフレーズ」になり、他のほとんどのページのタイトルは「タイトル - サイト名」になります。

function change_document_title_parts( $title ){
  $title['title'] = 'タイトル';
  $title['page']  = ''; 
  $title['tagline'] = 'キャッチフレーズ';
  $title['site'] = 'サイト名';

  return $title;
}
add_filter( 'document_title_parts', 'change_document_title_parts' );

実際に利用する場合は、必要に応じてパーツごとにページの種類によってカスタマイズすることができます。また、特定のページに対して特定のパーツの内容を変更したり、非表示にするということもできます。

以下は、フロントページ及びトップページでデフォルトで表示されるキャッチフレーズ($title['tagline'])を非表示にする例です。

function edit_document_title_parts ( $title ) {
  if ( is_home() || is_front_page() ) {
    unset( $title['tagline'] );
  }
  return $title;
}
add_filter( 'document_title_parts', 'edit_document_title_parts');

unset() を使うと配列の要素や配列自体を削除することができます。

条件分岐タグなどを使って柔軟にタイトルをカスタマイズすることができます。

以下は、個別ページで特定のカテゴリーに属する場合には文字列や get_the_date() を使って投稿の日時を追加したり、特定のタグやカテゴリーアーカイブページの場合に文字列を追加する例です 。

同じタイトルの投稿が複数ある場合などはタイトルに投稿日時などを追加することで自動的に生成されるタイトルタグが重複しないようにできます。

function my_edit_document_title_parts( $title ) {
  //個別ページの場合
  if ( is_singular() ) {
    if(in_category('event')) {
      //event というカテゴリーに属する場合はタイトルに(イベント活用例)と投稿年月日を追加
      $title['title'] .= '(イベント活用例)'.get_the_date('Y年n月');
    }elseif(in_category('attraction')) {
      $title['title'] .= '(アトラクション実施例)'.get_the_date('Y年n月');
    }else{
    ...
    }
  }else{
    //個別ページ以外の場合は、サイト名の部分のみ「イベント企画のABC」に変更
    $title['site'] = 'イベント企画のABC';
  }
  //特定のタグアーカイブページの場合
  if(is_tag('example')) {
    //example というタグアーカイブページの場合はタイトルに(実施例)を追加
    $title['title'] .= '(実施例)';
  }elseif(is_tag(array('food-event','promotion'))) {
    $title['title'] .= '(活用事例)';
  }
  //特定のカテゴリーアーカイブページの場合
  if(is_category(array('event-tool'))) {
    $title['title'] .= '(活用例)';
  }
  return $title;
}
add_filter( 'document_title_parts', 'my_edit_document_title_parts'); 

カスタムフィールドの値をタイトルとして出力(2)

以下は個別ページでカスタムフィールドにタイトル(キー名:my_title_tag)を設定している場合は、「タイトル - サイト名」の「タイトル」部分をカスタムフィールドの値に変更し、そうでない場合はデフォルトのシステムが生成するタイトルを表示する例です。

function edit_document_title_parts_with_cfv ( $title ) {
  //個別ページの場合
  if ( is_singular()  ) {
    //カスタムフィールドの値を取得
    $cf_title_tag = get_post_meta( get_the_ID(), 'my_title_tag', true );
    
    //カスタムフィールドに値が設定されている場合のみ変更
    if($cf_title_tag) {
      $title['title'] = esc_html( $cf_title_tag );
    }
    
  }
  return $title;
}
add_filter( 'document_title_parts', 'edit_document_title_parts_with_cfv');

カスタムフィールドの値をタイトルとして出力(1)の場合は、カスタムフィールドに値が設定されているかを判定しなくても問題ありませんでしたが、この場合は判定しないとカスタムフィールドを設定していないページのタイトル部分が空文字になってしまいます。

wp_get_document_title

現在のページのタイトルを取得します。現在のページの種類に応じて適切に処理されたタイトルの文字列が返ります(取得されます)。

wp_title() に代わって、Version 4.4.0 から導入されたページタイトルを生成する関数です。但し、値を表示(出力)するオプションはなく値を返すだけです。

wp_get_document_title()

パラメータ
なし
戻り値
WordPress により生成された(ページの種類により異なる)タイトルの文字列

ページの種類により、以下のようなタイトルが生成されます。

生成されるタイトルの例(一部)
ページ種類 表示されるタイトル
404ページ ページが見つかりませんでした – サイト名
検索ページ “キーワード” の検索結果 – サイト名
フロントページ サイト名 – キャッチフレーズ
固定ページ、投稿
カスタム投稿タイプなど個別ページ
ページのタイトル – サイト名
アーカイブページ(一覧ページ) タイトル – サイト名
タイトル – ページ番号 – サイト名(2ページ目以降の場合)

この関数のソースを見ると、以下のようにページ種類を判定する条件分岐タグを使ってページ種類によりタイトルを生成しています。

__() は翻訳関数です。日本語の翻訳は wp-content/languages の ja.po などに記載されています(このファイルを開くには Poedit などのエディタが必要です)。

・・・中略・・・
          
//タイトル文字列のパーツを格納する変数 $title(配列)
$title = array(
  'title' => '',  //$title['title'] の初期化
);

// If it's a 404 page, use a "Page not found" title.
//404ページの場合は「Page not found」の翻訳文字を $title['title']に格納
if ( is_404() ) {
  $title['title'] = __( 'Page not found' );

// If it's a search, use a dynamic search results title.
//検索ページの場合はキーワードと「Search Results for」の翻訳文字を $title['title']に格納
} elseif ( is_search() ) {
  /* translators: %s: search phrase */
  $title['title'] = sprintf( __( 'Search Results for &#8220;%s&#8221;' ), get_search_query() );
  
// If on the front page, use the site title.
//フロントページの場合は get_bloginfo('name','display')で取得するサイト名を $title['title']に格納
} elseif ( is_front_page() ) {
  $title['title'] = get_bloginfo( 'name', 'display' );
  
・・・中略・・・
/*
 * If we're on the blog page that is not the homepage or
 * a single post of any post type, use the post title.
 * ブログ投稿インデックスページか投稿や固定ページなどの個別ページの場合は 
 * single_post_title() の値(記事のタイトル)を $title['title'] に格納
 */
 } elseif ( is_home() || is_singular() ) {
    $title['title'] = single_post_title( '', false );

・・・以下省略・・・

タイトル文字列を格納する変数 $title は配列になっていて、以下のパーツに分かれています。

パーツ(要素) 内容
$title['title'] メインのタイトル文字列
(Title of the viewed page)
$title['page'] ページが分割されている場合のページ番号
(Page number if paginated)
$title['tagline'] フロントページの場合のキャッチフレーズ
(Site description when on home page)
$title['site'] フロントページでない場合に表示するサイト名
(Site title when not on home page)

ページが分割されている場合は、以下のようにページ番号を含むようになっています。ページ番号は $title['page'] に格納されます。

// Add a page number if necessary.
if ( ( $paged >= 2 || $page >= 2 ) && ! is_404() ) {
  $title['page'] = sprintf( __( 'Page %s' ), max( $paged, $page ) );
}

また、フロントページにはタイトルに「キャッチフレーズ」が、その他のページには「サイト名」が付加されるようになっています。

サイト名(サイトのタイトル)は get_bloginfo( 'name', 'display' ) により取得され、キャッチフレーズは get_bloginfo( 'description', 'display' ) により取得されます。

// Append the description or site title to give context.
  if ( is_front_page() ) {
    $title['tagline'] = get_bloginfo( 'description', 'display' );
  } else {
    $title['site'] = get_bloginfo( 'name', 'display' );
  }

document_title_parts のフィルター適用後は、$title は配列からセパレータ(デフォルトは '-')を付けた文字列に変換され、エスケープ処理等を経て呼び出し元に返されます。

$title = apply_filters( 'document_title_parts', $title );
//PHP の implode()関数で配列からセパレータで繋げた文字列に変換
$title = implode( " $sep ", array_filter( $title ) );
//特定の文字や記号を変換
$title = wptexturize( $title );
//特定のタグなどの変換
$title = convert_chars( $title );
//エスケープ処理
$title = esc_html( $title );
//WordPress と言う文字列の綴りを修正
$title = capital_P_dangit( $title );

return $title;

以下はこの関数のソース全体です。

function wp_get_document_title() {
  /**
   * Filters the document title before it is generated.
   * Passing a non-empty value will short-circuit wp_get_document_title(),
   * returning that value instead.
   * @since 4.4.0
   * @param string $title The document title. Default empty string.
   */
  $title = apply_filters( 'pre_get_document_title', '' );
  if ( ! empty( $title ) ) {
    return $title;
  }

  global $page, $paged;

  $title = array(
    'title' => '',
  );

  // If it's a 404 page, use a "Page not found" title.
  if ( is_404() ) {
    $title['title'] = __( 'Page not found' );

  // If it's a search, use a dynamic search results title.
  } elseif ( is_search() ) {
    /* translators: %s: search phrase */
    $title['title'] = sprintf( __( 'Search Results for &#8220;%s&#8221;' ), get_search_query() );

  // If on the front page, use the site title.
  } elseif ( is_front_page() ) {
    $title['title'] = get_bloginfo( 'name', 'display' );

  // If on a post type archive, use the post type archive title.
  } elseif ( is_post_type_archive() ) {
    $title['title'] = post_type_archive_title( '', false );

  // If on a taxonomy archive, use the term title.
  } elseif ( is_tax() ) {
    $title['title'] = single_term_title( '', false );

  /*
   * If we're on the blog page that is not the homepage or
   * a single post of any post type, use the post title.
   */
  } elseif ( is_home() || is_singular() ) {
    $title['title'] = single_post_title( '', false );

  // If on a category or tag archive, use the term title.
  } elseif ( is_category() || is_tag() ) {
    $title['title'] = single_term_title( '', false );

  // If on an author archive, use the author's display name.
  } elseif ( is_author() && $author = get_queried_object() ) {
    $title['title'] = $author->display_name;

  // If it's a date archive, use the date as the title.
  } elseif ( is_year() ) {
    $title['title'] = get_the_date( _x( 'Y', 'yearly archives date format' ) );

  } elseif ( is_month() ) {
    $title['title'] = get_the_date( _x( 'F Y', 'monthly archives date format' ) );

  } elseif ( is_day() ) {
    $title['title'] = get_the_date();
  }

  // Add a page number if necessary.
  if ( ( $paged >= 2 || $page >= 2 ) && ! is_404() ) {
    $title['page'] = sprintf( __( 'Page %s' ), max( $paged, $page ) );
  }

  // Append the description or site title to give context.
  if ( is_front_page() ) {
    $title['tagline'] = get_bloginfo( 'description', 'display' );
  } else {
    $title['site'] = get_bloginfo( 'name', 'display' );
  }

  /**
   * Filters the separator for the document title.
   * @since 4.4.0
   * @param string $sep Document title separator. Default '-'.
   */
  $sep = apply_filters( 'document_title_separator', '-' );

  /**
   * Filters the parts of the document title.
   * @since 4.4.0
   * @param array $title {
   *     The document title parts.
   *     @type string $title   Title of the viewed page.
   *     @type string $page    Optional. Page number if paginated.
   *     @type string $tagline Optional. Site description when on home page.
   *     @type string $site    Optional. Site title when not on home page.
   * }
   */
  $title = apply_filters( 'document_title_parts', $title );

  $title = implode( " $sep ", array_filter( $title ) );
  $title = wptexturize( $title );
  $title = convert_chars( $title );
  $title = esc_html( $title );
  $title = capital_P_dangit( $title );

  return $title;
}