WordPressの勉強2（自分用）

参考：『基礎からのWordPress』高橋のり

#ブログサイトのカスタマイズ
##ブログのトップページをカスタマイズ
###アイキャッチ画像を利用してレイアウト変更
・index.phpとsingle.phpの区別がつくようにしたい
→index.phpのレイアウトをサムネイル式にする
・index.phpの中ではコンテンツとなる画像や文章は、the contentというテンプレートタグ1つで出力されていた
→アイキャッチ画像と抜粋という機能を使い1ndex.phpのループ内を変更する

###アイキャッチ画像を使ってみる
・functions.phpに追加
`add_theme_support('post-thumbnails');`
・投稿の編集→アイキャッチ画像設定

###テンプレートファイルの修正
・アイキャッチ画像は記事本文の中に表示されるわけではなく、別途表示をする記述をテンプレートファイルの中でしないと表示されない
・抜粋は本文の一部を自動的に表示→日本語なら110文字
→WP Multibyte Patchプラグインを有効にすること
・index.phpにコードを追加・変更　p.187参照
・the_post_thumbnail(size)：設定されたアイキャッチ画像を表示する　【ループ内】
→size:画像の幅・高さをpx単位で指定できるほか、thumbnail, medium, largeのような値も使用可能
`the_post_thumbnail( array(100,100) );`
・the_excerpt()：抜粋を表示する　【ループ内】
→抜粋は、本文のはじめの110文字ではなく、投稿画面の「抜粋」に記述して表示させることもできる。入力枠は表示オプションを開いて抜粋をチェックすると表示される。

###フィルターフックと「続きを読む」のリンク
・functions.phpとindex.phpにコードを追加　p.189参照

###アイキャッチ画像がない場合の処理を考える
if文を使った条件分岐で、「もしアイキャッチ画像が設定されていなかったら、別途用意した画像を表示する」というコードを追加する
・画像の用意→imagesフォルダに保存
・index.phpのアイキャッチ画像を表示する部分を書き換える　p.190参照
→have_post_thumbnail

<b>もし…なら〜という考え方を習慣にすること。いろんな場面を想定してサイト構築をする習慣をつけておく。</b>

##カスタムヘッダーを使う
ヘッダーにインパクトのあるメインビジュアルを配置する

###カスタムヘッダーを有効にする
カスタムヘッダーを使うメリット＝管理画面から簡単に画像を変更できる
→最終的にはカスタムヘッダー機能と前述したアイキャッチ画像を組み合わせてページごとにヘッダー画像を設定してみる
→img要素として表示 または div要素などの背景画像として表示

###背景画像としてカスタムヘッダーを利用する
・画像の用意→imagesフォルダに保存

PHP基礎　関数の定義
`function 関数名(パラメータ){
 処理
}`
例
`function addition($a){
　$b = 10;
　echo $b + &a;
}`
実行するには
`addition(20);`
echoの代わりにreturnで戻り値を取得することもできる

・functions.phpにコードを追加
`&args = array (
    'width'         => 940,
    'height'        => 250,
    'header-text'   => false,
    'default-image' => get_template_directory_uri() . '/images/header.jpg',
);
add_theme_support( 'custom-header', $args );`
様々な項目を配列に記述
→header-text:ヘッダー画像をimg要素ではなく背景画像として使う場合にはtrue

・index.phpにコードを追加 &lt;!--header-->の直前
`<div id="header-image">
    <img src="<?php header_image(); ?>"
          height="<?php echo get_custom_header() -> height; ?>"
          width="<?php echo get_custom_header() -> width; ?>" alt="" />
</div>`
→->はオブジェクトから情報を取り出す場合に使用する記号

###ヘッダー画像をアップロードする
・外観→ヘッダー
・ヘッダー画像のサイズを自由にする場合
functions.phpのadd_theme_supportの配列に下記を追加
`'flex-height' => true,`
→アップロードした画像が自由にトリミングできるようになる
・削除はカスタムヘッダー画面の「ヘッダー画像を削除」の次にメディアライブラリで削除
　※バグを防ぐ

###カスタムヘッダーを背景画像として使う
・div要素などの背景画像として利用
・functions.phpのadd_theme_supportを以下のように書き換える
`&args = array (
    'width'         => 940,
    'flex-height'   => true,
    'height'        => 250,
    'header-text'   => true,
    'default-text-color' => 'ffffff',
    'default-image' => get_template_directory_uri() . '/images/header.jpg',
    'wp-head-callback' => 'header_style',
);
add_theme_support( 'custom-header', $args );`
→header-text:trueでヘッダー画像の中に文字を表示できる
→wp-head-callback:Webサイトのhead内にstyleタグを出力する関数を指定する
・functions.phpにheader_style関数を書き加える p.201参照
・header.phpの変更
`<div id="header-image">
    <p><?php bloginfo('description'); ?></p>
</div>`

###プレビューの表示項目を変更する
・管理画面のプレビューをWebサイトの表示と同じようにする
・キャッチフレーズのみにする
functions.php　add_theme_supportに追記
`'admin-preview-callback' => 'admin_header_image',`
→これでadmin_header_image関数を読み込む
→admin_header_image関数を定義　p.204参照
・プレビュースタイルを整える
functions.php　add_theme_supportに追記
`'admin-preview-callback' => 'admin_header_style',`
→admin-preview-callbackはプレビュー部分のスタイルシートを指定する関数を読み込むパラメータ
→admin_header_style関数を定義　p.205参照

<b>これ以降はまたimg要素 p.206</b>

##固定ページのヘッダーにアイキャッチ画像を使う
カスタムヘッダーを有効にすれば管理画面からヘッダー画像変更が可能だが、どのページも同じヘッダー画像が表示されてしまう
→アイキャッチ画像を利用して、固定ページのヘッダー画像を変更してみる

###アイキャッチ画像にサイズを追加
・function.phpに以下を追加
`add_image_size( 'header-image', 940, 250, true );`
・add_image_size('name', width, height, crop)
→name:一意な名前、width:幅の最大値、height:高さの最大値、crop:widthとheightで指定した幅と高さに合わせるために画像を切り抜くか、trueなら切り抜く、falseなら切り抜かない
→trueなら指定した幅と高さ通りに、falseならオリジナルの縦横比を維持したまま縦横どちらかに合わせて縮小される
・固定ページの編集でアイキャッチ画像を追加しておく

PHP基礎　論理演算子
・if文などで複数の条件を組み合わせて使いたいときに使う
>主な論理演算子
条件A&&条件B：条件Aと条件Bを両方満たす
条件A||条件B：条件Aと条件Bのどちらかを満たす
!条件A：条件Aを満たさない

・論理演算子は、複数を組み合わせて使用することもできる
→ex) 条件Aと条件Bの両方を満たすか、または条件Cを満たすかどうかを調べる場合
　　　(条件A && 条件B) || 条件C
　　　()を付けたものを優先してチェックする

###固定ページにアイキャッチ画像を表示
・header.phpのカスタムヘッダー部分のコードを変更　p.209参照
・get_the_post_thumbnail(id, size)：アイキャッチ画像を表示するためのimg要素を出力する　【ループ問わず】
　→id:投稿のID

###トップページと固定ページ以外では、ヘッダー画像そのものを非表示に
・ヘッダー画像が必要ないページで非表示にする
・header.phpのカスタムヘッダー部分のコードを変更　p.210参照
`if (is_home() && !is_paged() || is_page()):`
→&lt;div id="header-image">自体を「トップページと固定ページのとき」のみという条件分岐で囲む
→is_home:ブログのメインページかどうかを判断する条件分岐タグ
→is_paged:2ページ目,3ページ目など複数にわたるページがどうかを判断する条件分岐タグ
　→2つを合わせて「ブログのメインページかつ2ページ目以降でない場合」という条件になる＝トップページ
→is_page:固定ページかどうかを判断してくれる条件分岐タグ

##パンくずリストの作成
###パンくずリストの仕組み
・現在のページから他のページの情報（タイトルやリンク）を表示しなければならない
・パンくずリスト：サイトの階層を示すナビゲーションの一種。ヘンゼルとグレーテルのパンくず。
　ユーザーにとっては自分が今サイトのどこにいるのか把握しやすくなるため、多くのWebサイトで採用されているUI

###ページによって表示する内容が異なる
・現在いるページから上層のページを取得してリンクやタイトルを表示
・ページの種類によって表示する内容は異なる
→【ブログの個別記事】カテゴリーを表示する
<i>Home > 親カテゴリー > 子カテゴリー > 記事のタイトル</i>
→【固定ページ】WordPressには固定ページがあり、固定ページには親子関係がつけられる。固定ページを表示しているときには、パンくずリストにはカテゴリーではなく祖先ページを表示する必要がある。
<i>Home > 親ページ > 子ページ > 記事のタイトル</i>
→【その他のページ】カテゴリーのページ、タグのページ、検索結果のページ、404ページなど

###現在のページから祖先となるカテゴリーや固定ページを取得する
・今までは現在表示されているページの情報を取得し表示するものばかりだった
・祖先の情報を取得し表示できるようになれば、サイドバーのローカルナビゲーションをつけることなどできる

###WordPressのページ
###ページの種類と条件分岐タグ
>ブログのトップページ（メインページ）：is_home
固定ページ：is_page
個別記事ページ：is_single
カテゴリーのアーカイブページ：is_category
タグのアーカイブページ：is_tag
検索結果表示ページ：is_search
404 Not Foundページ：is_404
日付ベースのアーカイブページ：is_date
投稿者のアーカイブページ：is_author
添付ファイルページ（投稿画面→メディアを挿入→リンク先で設定可能）：is_attachment

###パンくずリストの骨組みを作る
・header.phpのヘッダー画像を出力している部分の直前に記述　p.216参照
→トップページにはパンくずリストは必要ないのでif文に!is_home()という条件をつけて分岐
→まずHOMEを作る

・各ページの条件分岐を一気に用意する p.218参照

###検索ページ／タグページ／404ページ
・検索ページでは、「（キーワード）で検索した結果」と表示することにする
・タグページでは、「タグ：（タグ名）」と表示することにする
・404ページでは、「404 Not Found」と表示することにする（取得の必要なし）
→まとめたコード　p.219参照

###日付アーカイブページ
・「年別」「月別」「日別」の3つのページが存在する
→まず表示されているページがどのアーカイブなのかを判断する
→is_year, is_month, is_dayという条件分岐タグ（is_dateの中）
・どんなデータが必要か
→2014（年）、4（月）などの文字列とアーカイブページのURLが必要になる

###変数$wp_query
・WordPressがページを表示しているとき、そのページの情報を格納している変数（自動）
　query：問い合わせ
・変数の内容の確認 header.phpの最後に記述
`<pre>
    <?php print_r($wp-query); ?>
</pre>`
※print_r：開発段階で使われる、変数の詳細をわかりやすい状態で表示するPHPの関数
・表示されるWP_Query Objectの中に、query_varsという配列がありyear, monthnum, dayなどのラベル（インデックス）の中に「2014」、「4」といった値が代入されている
→この記事が投稿された年月日の情報を保持している

###query_varsの値を参照するget_query_var
・get_query_var('var')：$wp_queryが持つ情報を取得する
　var:取得したい情報のインデックス
`<?php get_query_var('year') ?>`

###日付別のパンくずリストを作る
・まずは日別のアーカイブのパンくずリスト　p.223参照
・リンクの取得
　get_year_link(year)：年別アーカイブページのURLを取得、パラメータ省略で今年
　get_month_var(year, month)：月別アーカイブページのURLを取得、パラメータ省略で今年今月
　get_day_link(year, month, day)：日別アーカイブページのURLを取得、パラメータ省略で今年今月今日
・is_dateならばというif文の中に上記3つのif文が入れ子になっているのでその閉じタグが必要
・完成した日付別アーカイブのパンくずリスト　p.225参照

###カテゴリーアーカイブのパンくずリスト
・カテゴリーには親子関係がある→階層があるということ→祖先カテゴリーまで表示する
・どんなデータが必要か
→現在表示されているカテゴリーの名前、祖先カテゴリーの有無、それらの名前とURL
・query_vars配列にはカテゴリーに関する情報が含まれていない
→get_queried_objectという関数を利用してカテゴリー情報を取得
・print_rでオブジェクトの詳細を確認（今回は取得したオブジェクトを$catという変数に入れてみる）
`<pre>
    <?php $cat = get_queried_object(); print_r($cat); ?>
</pre>`
・必要なID情報 cat_name, cat_ID, parentなど

PHP基礎　オブジェクトへのアクセス
・オブジェクトがもつ情報はプロパティとよばれ、プロパティ名と値が1セットとなってオブジェクト内に格納されている（配列におけるキーと値のセットのような）
　ex)get_queried_object()関数が返すオブジェクトならばcat_nameがプロパティ名
・プロパティにアクセスするには->を使う
`<pre>
     <?php $cat = get_queried object(); print_r($cat->cat_name); ?>
</pre>`

PHP基礎　比較演算子
・if文やwhile文で条件分岐タグを使ってきたが、PHPのプログラムでは比較演算子というものを使うのが普通
・比較演算子は名前のとおり2つの値を比較して結果をtrue,falseで返す
>主な比較演算子
a == b  aとbが等しい
a != b　aとbが等しくない
a < b　aはbより少ない
a > b　aはbより多い
a <= b　aはbより少ないか等しい
a => b　aはbより多いか等しい
※等しいは==なことに注意

ex)if($a >= 3)→変数$aの値が3以上だったら

###親カテゴリーのチェック
・親カテゴリーの有無
→parentプロパティの番号をチェックする
・この数字はカテゴリーのIDで、整数
　0なら親カテゴリーはなし
・親カテゴリーをチェックするための骨組み　p.228
・$catのparentプロパティの値が0でなければ＝もし親カテゴリーがあれば
・現在のカテゴリーの名前を表示

###カテゴリーの祖先を取得する
・カテゴリーの階層は親の更に上がある場合がある
→get_ancestors関数を使ってまとめて取得
・get_ancestors(id,type)：祖先となる要素のIDを配列にして取得
→type:祖先を取得するタイプをcategoryまたはpage（固定ページ）のいずれかで指定
`<?php $ancestors = get_ancestors( $cat -> cat_ID, 'category' ); ?>`
→$ancestorsという変数（配列）に祖先カテゴリーのIDが格納される
・parent_rで$ancestorsの詳細を確認
→作成される配列のインデックスは０から始まる整数が自動的に設定される
→それぞれの取得には$ancestors[0]…
・上記を書き換える
`<?php $ancestors = array_reverse(get_ancestors( $cat -> cat_ID, 'category' )); ?>`
→array_reverse：配列の中の要素を逆の順番にする

PHP基礎 foreach文
・今まで処理を繰り返すためにはwhile文を使ってきたが、新たにforeach文
・繰り返す条件は「配列の要素の数だけ」という便利な構文
`foreach ($a as $b) {
配列$aの要素の数だけ繰り返す処理
}`
→配列$aの1つ1つの要素を、変数$bとして扱うという意味
→$aの値を$bに代入しながら繰り返すといった処理
`foreach ($fruits as $fruit) { echo $fruit; }`
→繰り返すたびに配列$fruitの値を参照しながら変化

###カテゴリーの名前やURLを取得する
・get_cat_name($id)：カテゴリーの名前を取得する
・get_cat_link($id)：カテゴリーのURLを取得する
・完成したカテゴリーアーカイブページのパンくずリスト　p.232参照

###投稿者ページのパンくずリスト
・必要なもの→投稿者の名前のみ（管理画面の「ユーザー」→「あなたのプロフィール」→「ブログ上の表示名」）
・the_author_meta(field, user_id) ：指定されたユーザー情報を表示
→field:表示したいユーザー情報の種類を指定。ユーザー名の場合は'display_name'
・user_idとは、ログイン時などに使用するIDではなくWordPressによって自動的につけられるID
→get_query_var関数で取得
・完成した投稿者ページのパンくずリスト
`<?php elseif (is_author()) : ?>
<li>投稿者：<?php the_author_meta('display_name', get_query_var('author')); ?><li>`

###固定ページのパンくずリスト
・固定ページも親子関係を作ることができる
→固定ページの投稿画面「ページ属性」
・必要なもの→現在ページのタイトル、祖先ページのタイトルとURL
→get_queried_object関数
→しかし、ページに関連する詳細情報はWordPress側で$postという変数にまとめられている
・print_rで$postの内容をチェック
→ID, post_parent(親のID), ancestors(祖先ページが配列で格納)
・完成した固定ページのパンくずリスト　p.236参照

###添付ファイルページのパンくずリスト
・ページのタイトル（画像ファイルのタイトル）、元記事ページ
・親となる元ページは　$post -> post_parent
・完成した添付ファイルページのパンくずリスト　p.237参照

###個別記事ページのパンくずリスト
・カテゴリーと共に表示する
・現在表示している記事のタイトル、記事が投稿されているカテゴリー・祖先カテゴリーの名前とURL
・get_the_category、get_category_link　カテゴリーアーカイブp.231参照
・完成した個別記事ページのパンくずリスト　p.240参照

###それ以外のページの処理
`<?php else: ?>
<li><?php wp_title('', true); ?></li>`

###パンくずリストを関数としてまとめる
・header.phpのようなテンプレートファイルに長いコードが記述されているのはメンテナンス性がよくない
→functions.phpへ

PHP基礎　変数のスコープ
・変数には有効範囲がある＝変数のスコープ
・関数の外にある変数はそのままでは使えない
・関数の中に書いた変数はローカル変数＝その関数内でしか使えない
・関数の外にある変数を内で使用するには
`$this-year = date(Y);
function display_dc(){ global $this_year; echo '今年は'._$this_year.'年です。'; }`

```lang:functions.php
<?php function breadcrumb() { global $post ; $str = ''; 
  if (!is_home() && !is_admin()) {
    $str.= '<div id="breadcrumb" class="clearfix">';
    $str.= '<ur style="list-style:none;">';
    $str.= '<li><a href="'. home_url('/') .'/">HOME</a></li>';
    $str.= '<li>&gt;</li>';

    if (is_search()) {
      $str.= '<li>「'. get_search_query() .'」で検索した結果</li>';
    } elseif (is_tag()) {
      $str.= '<li>タグ：'. single_tag_title( '' , false). '</li>';
    } elseif (is_404()) {
      $str.= '<li>404 Not found</li>';
    } elseif (is_date()) {
        if (is_day()) {
          $str.= '<li><a href="'. get_year_link(get_query_var('year')). '">'. get_query_var('year') .'年</a></li>';
          $str.= '<li>&gt;</li>';
          $str.= '<li><a href ="'. get_month_link(get_query_var('year'), get_query_var('monthnum')). '">'. get_query_var('monthnum') .'月</a></li>';
          $str.= '<li>&gt;</li>';
          $str.= '<li>'. get_query_var('day') .'日</li>';
        } elseif (is_month()) {
          $str.= '<li><a href="'. get_year_link(get_query_var('year')). '">'. get_query_var('year') .'年</a></li>';
          $str.= '<li>&gt;</li>';
          $str.= '<li>'. get_query_var('monthnum') .'月</li>';
        } else {
          $str.= '<li>'. get_query_var('year') .'月</li>';
        }
    } elseif (is_category()) {
      $cat= get_queried_object();
      if ($cat -> parent !=0) { $ancestors = array_reverse(get_ancestors( $cat -> cat_ID, 'category' )); foreach ($ancestors as $ancestor) {
          $str.='<li><a href="'. get_category_link($ancestor) .'">'. get_cat_name($ancestor) .'</a></li>';
          $str.='<li>&gt;</li>';
      }
      }
      $str.='<li>'. $cat -> name .'</li>';
    } elseif (is_author()) {
      $str.= '<li>投稿者：'. get_the_author_meta('display_name', get_query_var('author')).'</li>';
    } elseif (is_page()) {
      if ($post -> post_parent !=0) { $ancestors = array_reverse(get_post_ancestors( $post -> ID )); foreach ($ancestors as $ancestor) {
          $str.='<li><a href="'. get_permalink($ancestor) .'">'. get_the_title($ancestor) .'</a></li>';
          $str.='<li>&gt;</li>';
      }
      }
      $str.='<li>'. $post -> post_title .'</li>';
    } elseif (is_attachment()) {
          $str.='<li>'. $post -> post_title .'</li>';
    } elseif (is_single()) { $categories = get_the_category($post -> ID); $cat = $categories[0];
      if ($cat -> parent !=0) { $ancestors = array_reverse(get_ancestors( $cat -> cat_ID, 'category' )); foreach ($ancestors as $ancestor) {
          $str.='<li><a href="'. get_category_link($ancestor) .'">'. get_cat_name($ancestor). '</a></li>';
          $str.='<li>&gt;</li>';
      }
      }
      $str.='<li><a href="'. get_category_link($cat -> term_id) .'">'. $cat -> cat_name .'</a></li>';
      $str.='<li>&gt;</li>';
      $str.='<li>'. $post -> post_title .'</li>';
    } else {
      $str.='<li>'. wp_title('', true) .'</li>';
    }
    $str.='</ul>';
    $str.='</div>';
  }
  echo $str;
}
?>
```

・functionを使って、breadcrumbという名前で関数を宣言
・変数postをglobal宣言して関数内で利用
・header.phpにはHTMLタグとPHPコードを混在させていたが、全てPHPで
・liと記述していたタグをシングルクォート(')、またはダブルクォーテーション(")で囲み、文字列として変数に代入
・文字列はstrという変数に次々とつなげて格納していく
→まずはstr=''として空の変数を作り、以降はstr.=として文字列をつなげていく（.は文字列を連結してくれる演算子）
→最後のecho $strで一気に出力する（PHP）
・最後にechoで出力するのでecho home_urlのechoは消去
・the_search_queryはget_search_queryというように「表示」のテンプレートタグから「取得」のテンプレートタグに変更

・header.phpに作成した関数を記述する
`<?php breadcrumb(); ?>`

##関連記事を表示する
・ブログ個別記事ページに同じカテゴリーの記事を関連記事として表示する
→サブループ

###複数のWordPressループ
・関連記事→同じカテゴリーの記事、同じタグがついている記事など
・同じカテゴリーの記事を表示してみる
・トップページと同じくWordPressループを使って表示
WordPressのループおさらい
`if (have_post()) :
while (have_posts()) : the_post();
ループ
endwhile; ?>
else :
記事がなかった場合の処理
endif;
`
・特定のカテゴリーだけを表示するWordPressループ
`$args = array (
'category__in' => array( 1, 4 ),
'paged' => get_query_var('paged')
);
query_posts( $args );
if (have_posts()) : 
while (have_posts()) : the_post();
ループ
endwhile; ?>
else : 
記事がなかった場合の処理
endif;
wp_reset_query();`
→query_posts(query)：WordPressループの対象を条件により絞り込む
→上記では配列argsの中に条件となるパラメータを代入
　→category__inでは表示したいカテゴリーのIDを指定
　→pagedは、もし2ページ目や3ページ目の場合に、「2」や「3」など何ページ目かを指定する
→wp_reset_queryはquery_postsで変更したWordPressループ（カスタムループ）を元のWordPressループに戻すための記述【必ず記述する】

###メインループとサブループ
・1つのページで複数のループを使うために、注意しなければいけないこと
→query_postsはメインループにしか使えない

###サブループ用のオブジェクトを作成する
・サブループを利用するため、サブループ用のWordPressオブジェクトを作成する（投稿記事の集まりのようなもの）
・WordPressオブジェクトの作成
`$args = array (
条件
);
$変数名 = new WP_Query($args);`
・WP_Query：オブジェクトを作る関数のようなもの。パラメータに与える配列により、作成されるWordPressオブジェクトの内容が変化する
・同じカテゴリーの記事を関連記事とするための配列
`＄args = array (
'post__not_in' => array(＄post -> ID),
'category__in' => $category_ID,
'posts_per_page' => 3,
'orderby' => 'rand',
);
＄my_query = new WP_query(＄args)`
・post__not_in：表示したくない配列がある場合にIDを配列に入れて指定（今回はメインループで表示されている個別記事を指定）
　※このようにPHPでは配列の中に配列を入れることも可能でこれを多次元配列という
・category__in：特定のカテゴリーを表示したい場合に、カテゴリーIDを配列に入れて指定（今回は＄category_IDに複数のカテゴリーIDを格納）
・posts_per_page：何件表示するかを指定できる。（今回は3件）
・orderby：記事をどんな順番で表示するかを文字列で指定（今回はランダム(rand)、他に日付順(date)、コメントの多い順(comment_count)、最終更新日順(modified)）
→「現在表示されている記事を除く、任意のカテゴリーを3件、ランダムな順番で表示する」

###サブループを作る
・category_ID→現在表示されているメインループの記事から、投稿されているカテゴリーを取得したものを、配列として代入する
・get_the_category：現在投稿されている記事のカテゴリーの詳細を取得する・記事によってはカテゴリーは複数あるはず→foreach文（配列の要素の数だけ繰り返し処理）を使って、カテゴリーIDだけの新しい配列をつくる
`＄categories = get_the_category(＄post -> ID);
＄category_ID = array();
foreach (＄categories as ＄category):
array_push( ＄category_ID, ＄category -> cat_ID );
endforeach ;`
→array_pushで要素を1つずつ追加していく（配列の一番最後に要素を追加する）

###サブループを記述する
・サブループの骨組み
`if( ＄my_query -> have_posts() ):
while (＄my_query -> have_posts()) : ＄my_query -> the_post();
endwhile;
else:
endif;
wp_reset_postdata();`
→今まで見てきたWordPressループと似ているが、操作の対象は先ほど作成したmy_query
→have_postsやget_postはオブジェクトに属する関数（メソッドと呼ぶ）
→オブジェクトに属するものはなんでも->でアクセスが可能
・メインループとは別の操作対象を用意してからループさせる
・一番最後にwp_reset_postdataでリセットする

```lang:single.php（完成したループ）
      <?php $categories = get_the_category($post -> ID); $category_ID = array(); foreach ($categories as $category): array_push( $category_ID, $category -> cat_ID ); endforeach ; ?>
      <?php $args = array (
              'post__not_in' => array($post -> ID),
              'category__in' => $category_ID,
              'posts_per_page' => 1,
              'orderby' => 'rand',
              'paged' => 2 //pagedの実験
            );
            $my_query = new WP_Query($args); ?>

        <div class="related-posts">
        <h3 id="related">Related Posts</h3>
        <?php if ($my_query -> have_posts() ): ?>
          <ul id="related-posts">
          <?php while ($my_query -> have_posts()) : $my_query -> the_post(); ?>
          <li class="clearfix">
            <div class="content-box">
              <h4><a href="<?php the_permalink() ?>"><?php the_title(); ?></a></h4>
              <p class="date"><?php echo get_the_date(); ?></p>
              <?php the_excerpt(); ?>
            </div>

            <p class ="thumbnail-box">
              <a href = "<?php the_permalink() ?>" title = "「<?php the_title(); ?>」の続きを読む">
                <?php if (has_post_thumbnail()): the_post_thumbnail(array(100, 100)); ?>
                <?php else : ?>
                  <img src = "<?php echo get_template_directory_uri(); ?>/images/noimage.gif" width = "100" height = "100" alt = "" />
                <?php endif; ?>
              </a>
            </p>
          </li>
          <?php endwhile; ?>
          </ul>
        <?php else : ?>
          <p>関連する記事はありませんでした...</p>
        <?php endif; ?>
        </div>
       <!-- /related-posts -->
 
     <?php wp_reset_postdata (); ?>
     <?php comments_template(); ?>
     <?php endwhile; ?>
     <?php else : ?> 
      <h2>記事はありません</h2>
        <p>お探しの記事は見つかりませんでした</p>
     <?php endif; ?>
```
・メインループの中、「次の記事・前の記事へのナビゲーション」と「コメント欄」の間にサブループを作っている　p.251参照
・トップページと同じように、タイトル、抜粋(the_excerpt)、アイキャッチ画像(the_post_thumbnail)を表示
・細かい機能追加（タイトルとリンク、日付）とスタイル用のdivタグを追加して完成

###カスタムフィールドとは
・投稿1つ1つにつけることができる「名前」と「値」がセットになったフィールドのこと
・投稿の編集画面「カスタムフィールド」で各記事に名前と値を入力（ここでは名前をshort_descriptionにする）
・single.phpのコードの中のthe_excerptの部分を書き換える
`<p><?php echo get_post_meta(＄post -> ID, 'short_description', true); ?></p>`
・アイデア次第でいろんなことに利用することができ、複数利用も可能
→EX)アイキャッチとは別の画像を使いたい場合
　名前：other_image
　値：画像アドレス
`<img src="<?php echo get_post_meta($post -> ID, 'other_image', true); ?>" alt="" />`
　とすれば画像を表示させることも可能
・このように「名前」と「値」をセットにして、テンプレートファイルの中で利用することができる
・表示または取得するために必要なテンプレートタグ
→get_post_meta(id, name, single)：カスタムフィールドの値を取得する
　→single:単一の値として使用する場合はtrue,配列として使用する場合はfalseを指定。デフォルトはfalse
　　→一つの名前に複数の値を入れることができるため、戻り値を配列としても利用できる
　→idには記事のIDを指定。通常は＄post -> IDで取得できるがループ外の場合は事前にglobal ＄postとグローバル宣言をしておくこと

##コメント欄のテンプレートを変更する

###コメント欄の詳細設定
・wp_list_comments：自動的にコメント一覧を表示するためのHTMLを出力
→デフォルトは、コメントとピンバック（トラックバック）を区別せず投稿された順番で示す
・メニューから「設定」→「ディスカッション」でいろいろな設定が可能
→ネストを表示する？＝ネストされたリストで出力するかどうか
・コメントをスレッド形式にする（返信コメント）
→ネストさせた場合は、CSSでオフセットさせる
・今回は返信コメントのスレッド化、コメントが多い場合にページを複数に分けるレイアウト、コメントとピンバックを分けて別々に表示するようにしてみる

###コメント一覧をオリジナルマークアップにする
・デフォルトのコメント一覧と違って、コメントとピンバックを分けて表示する
・コメントのみを表示させるようにする
`wp_list_comments( 'type' = 'comment' ) ;`
・独自のマークアップでコメント一覧を作成する
→そのためにwp_list_commentsにコールバック関数を指定する
　→コールバック関数：実行する処理を他の関数に移すための仕組み
　　（相手に電話して電話番号を伝えたあとかけ直してもらうのに似ている）
　　ある関数から別の関数を呼び出し、目的の処理自体は呼び出した関数に行ってもらうという仕組み
・wp-list_commentsにコールバック関数を指定する場合
`wp_list_comments( 'callback' = '関数名' );`
→オリジナル関数をつかえば独自のマークアップでコメント一覧を出力できるということ

・comments.phpのコメントを出力している部分を次のように書き換える
`    <?php $args = array ( 'type' => 'comment', 'callback' => 'my_comment_list' ); ?>  
    <ol class="commets-list" id="custom-commments">
    <?php wp_list_comments($args); //コメント一覧を表示 ?>
    </ol>`

・functions.phpにmy_comment_listという関数を作成していく

```lang:functions.php
<?php function my_comment_list($comment, $args, $depth) { $GLOBALS['comment'] = $comment; ?>
  <li <?php comment_class(); ?> id="comment- <?php comment_ID(); ?>">
    <div class="clearfix">
      <div class="comment-author clearfix">
        <?php echo get_avatar( $comment -> comment_author_email, 65); ?>
        <cite><?php comment_author_link(); ?><span class ="says">says:</span></cite>
        <p class="comment-meta">
          <a href="<?php echo esc_url( get_comment_link( $comment -> comment_ID )) ?>"><?php comment_date(); ?><span><?php comment_time(); ?></span></a><br />
          <?php edit_comment_link('(編集)'); ?>
        </p>
      </div>
      <div class="comment-body">
        <?php if($comment -> comment_approved == '0') : ?>
        <p><em>あなたのコメントは承認待ちです。</em></p>
        <?php endif; comment_text(); ?>
        <p class="reply">
        <?php comment_reply_link(array_merge( $args, array('reply_text' => '返信', 'depth' => $depth, 'max_depth' => $args['max_depth']))); ?>
        </p>
      </div>
    </div>
  </li>
<?php } ?>
```

・まずは変数＄commentをスーパーグローバル関数にして、いつでもアクセスできるようにしておく（＄commentには記事に投稿されているコメントの詳細情報が格納されている）
・liタグの終了タグは不要→コメントが入れ子になる可能性があるため。WordPressが挿入してくれるので問題ない
・comment_class関数：コメントに応じてさまざまなクラスを自動でつける（偶数番目even、奇数番目odd、ブログユーザーbypostauthor　→交互に・ユーザーだけスタイルを変更することが可能）
・comment_ID関数：自動につけられるID。コメントには必ず「comment-X」の形式でIDをつけること（パーマリンクに使用するため）

###アバターを表示する
・get_avator(mail, size, default_avatar, alt)：Gravatarのアバターを表示するimgタグを出力する

###コメント主名やコメント投稿日時、編集リンク
・comment_author_link：コメント主の名前を表示してくれるだけでなく、URLがあればリンクを貼った状態で表示
・comment_date：日付を返す
・comment_time：時間を返す
・投稿日時をコメントURLのリンクで囲んでいる
・edit_comment_link('str', 'before', 'after')：コメント編集画面へのリンクを表示する【ループ内】
→str:リンク文字列の指定、before:リンクの直前に出力するコードやテキスト、after:リンクの直後に出力するコードやテキスト
→コメント編集画面へのリンクを表示（ログインしているユーザーにしか表示されない）

###コメントの内容、返信用のリンクを表示する
・comment_text：コメント本文を表示。pタグも一緒にマークアップされる
・WordPressのコメントは基本的に承認制
→未承認のコメントは＄commentオブジェクトのcomment_approvedプロパティに0が入っているため、これを使って条件分岐をし、未承認のコメントには承認待ちの文を表示する
・comment_reply_link：コメントの返信リンクを表示する
→管理画面での設定を反映するため、array_merge〜のタグを記述する
→reply_text:表示するテキストを変更できる

###次のコメントページ、前のコメントページへのリンク
・コメント一覧を複数のページに分ける→ディスカッション設定
・必要になるのが次ページ、前ページへのリンク（ナビゲーション）
→comments.phpのコメント一覧を表示する部分の下に追加
`    <?php $args = array ( 'type' => 'comment', 'callback' => 'my_comment_list' ); ?>  
    <ol class="commets-list" id="custom-commments">
    <?php wp_list_comments($args); //コメント一覧を表示 ?>
    </ol>
    <?php if ( $wp_query -> max_num_comment_pages > 1 ) : ?>
    <div class="comment-page-link">
        <?php $args = array( 'prev_text' => '&laquo; Prev', 'next_text' => 'Next &raquo;' ); paginate_comments_links($args); ?>
    </div>
    <?php endif; ?>`

###ピンバックの一覧を表示する
・ピンバックのみを一覧表示する
・コメントナビゲーションとコメントフォームの間にピンバックの一覧を表示していく
・骨組み
`<?php foreach ($comments as $comment) : if (get_comment_type() != 'comment' ): 
  処理
endif;
endforeach;
?>`
・＄commentsにはコメント一覧の詳細が格納されている。それをforeach文でループさせながらif文を使ってコメント以外を拾う
・get_comment_type：コメントの種類を取得する関数
→comment/trackback/pingback　get_comment_type() != 'comment'とすることで残り2つだけを拾うことができる
・ピンバック一覧は返信リンクも必要ないため、単純にリストで一覧表示する

```lang:comments.php
<?php $str = '<h3 id="trackbacks">Trackback</h3>'; $str .='<ol class="trackback-list">'; $i = 0; ?>
<?php foreach ($comments as $comment) : if (get_comment_type() != 'comment' ): ?>
  <?php $str .='<li class="clearfix"'. 'id="comment-'. get_comment_ID() . '">';
        $str .='<div class="trackback-author">';
        $str .='<cite>' . get_comment_author_link() . '</cite>';
        $str .='<p class="comment-meta">' . '<a href="' . esc_url(get_comment_link ( $comment -> comment_ID )) .'">' . get_comment_date() .'<span>'. get_comment_time() .
          '</span><a class="edit" href="' . get_edit_comment_link() . '">(編集)</a></span></p>';
        $str .='</div>';?>
  <?php $str .='<div class="trackback-body">'; if ($comment -> comment_approved =='0') : $str .= '<p class="attention"><em>' . 'あなたのトラックバックは承認待ちです。' . '</em></p>'; ?>
  <?php endif; ?>
  <?php $str .='<p>'. get_comment_text() .'</p>';
        $str .='</div>';
        $str .='</li>';
        $i++; ?>
<?php endif; ?>
<?php endforeach; ?>
<?php $str .='</ol>'; ?>
<?php if($i > 0): { echo $str; } endif;  ?>
```
・foreach文を記述する前に見出しやolタグの開始タグが必要
→変数strに代入するのはなぜか：コメント一覧の中にピンバックやトラックバックが必ず含まれているとは限らないため
→含まれているときのみ表示させるために、まず変数strに代入しておいて、最終的に表示する必要があるときにechoで出力
・変数iに0を入れている→カウンターとして利用し条件分岐の仕組みに利用する

###li要素の中の仕組みを組み立てる
・ピンバックの送信元、送信日時を表示する部分
・変数strに連結代入するため、表示のテンプレートタグではなく取得のテンプレートタグを使う
・comment_author_link → get_comment_author_link（コメント主を取得）
・comment_date → get_comment_date（コメント投稿日を取得）
・最終的にechoで表示

###ピンバック・トラックバックの有無を判断する
・変数iはピンバックやトラックバックの数を数えるためのカウンター
・＄i++;というコードは、「＄iの値に1を足す」というコード
→ピンバックやトラックバックがあるたびに変数iの値は1ずつ増えていく
・最終的にolタグの終了タグを代入し、カウンター＄iが１以上であれば、変数strをechoで一気に出力

##コメントフォームのカスタマイズ
###テンプレートタグcomment_formの仕組み
・コメントフォームにはコールバック関数を指定することができない
→どのようにしてcomment_formによって出力されるHTMLを変更すればいいか
→フィルターフック
・デフォルトのマークアップを含むPHPのコードはWordPressのコアファイル(wp-includes/comment-template.php)に記述されている
→翻訳のためのファイル(wp-content/languageフォルダ)で日本語で表示
→今回ははじめから日本語で記述する
→コアファイルを直接編集するのはタブー

###フィルターフックを利用する
・フィルターフック：ある処理を実行するときに、指定の関数をひっかけて（フックして）実行するという仕組み
→特定の処理をするときに、別途用意した関数を読み込み、処理を上書きするようなもの

・まずはfunctions.phpに以下を記述
`add_filter('comment_form_default_fields', 'comment_form_custom_fields');`
・特定のフィルターフックに関数をフックさせるためには、add_filter関数を使う
→comment_form_default_fieldsというフィルターフックを実行する際に、用意したcomment_form_custom_fieldsという関数をフックするという意味
・comment_form_custom_fields関数をfunctions.phpに定義

```lang:functions.php
<?php add_filter('comment_form_default_fields', 'comment_form_custom_fields'); ?>
<?php
function comment_form_custom_fields($fields) { 
  $commenter = wp_get_current_commenter(); 
  $req = get_option( 'require_name_email' ); 
  $aria_req = ($req ? " aria-required='true' " : '' );
$fields['author'] = '<p class="comment-form-author"><label for="author">お名前</label>' . ( $req ? '<span class="required">*</span>' : '' ) . '<input id="author" name="author" type="text" value="' . esc_attr( $commenter['comment_author'] ) . '" size="30"' . $aria_req . ' /></p>';

  $fields['email'] = '<p class="comment-form-email"><label for="email">メールアドレス</label>' . ($req ? '<span class="requied">*</span><span class="small">（メールアドレスは公開されません）</span>' : '' ) .'<input id="email" name="email" type="text" value="' . esc_attr( $commenter['comment_author_email'] ). '"size="30"'. $aria_req . ' /></p>'; 
  $fields['url'] = ''; 
  return $fields;
}
?>
```
・＄commenter~＄aria_req 入力済みの値(value)があったときに、その値を取得したり、名前やメールアドレスが必須項目に指定されているかどうかを取得するための記述
・Name →　お名前
・spanでメールアドレス入力欄の前にメールアドレスは公開されませんと表示
・Webサイトの項目を削除（空文字を指定することで削除できる）

・comments.php
`<?php comment_form(); ?>`

###その他のラベルなどを変更する
・「コメントを残す」という見出しをはじめ、いろんな部分のラベルのテキストなどを変更
→フィルターフック
→add_filter関数をfunctions.phpに記述
`add_filter('comment_form_defaults', 'comment_form_custom');`

・comment_form_custom関数を記述

```lang:functions.php
<?php add_filter('comment_form_defaults', 'comment_form_custom'); ?>
<?php function comment_form_custom($form) {
  global $user_identity, $post;
  $req = get_option( 'require_name_email' );
  $required_text = '<span class="required">*</span>が付いている項目は、必須項目です！';

  /* コメントフォームtextarea */
  $form['comment_field'] = '<p class="comment-form-comment"><label for="comment">コメント</label><textarea id="comment" name="comment" cols="45" rows="8" aria-required="true"></textarea></p>';
  /*  要ログイン時 */
  $form['must_log_in'] = '<p class="must-log-in">' . sprintf('コメントを残すには、<a href="%s">ログインしてください。', wp_login_url( apply_filters( 'the_permalink', get_permalink( $post->id ) ) ) ). '</p>';
  /* ログイン時 */
  $form['logged_in_as'] = '<p class="logged-in-as">' . sprintf('<a href="%1$s">%2$s</a> としてログインしています。<a href="%3$s" title="Log out of this account">ログアウト</a>しますか？', admin_url( 'profile.php' ), $user_identity, wp_logout_url(apply_filters( 'the_parmalink' ,get_permalink($post->id ) ) ) ). '</p>';
  /*コメントフォームの前に表示するテキスト */
  $form['comment_notes_before'] = '<p class="comment-notes">' . ($req ? $required_text : '') .  '</p>';
  /*コメントフォームの後に表示するテキスト*/
  $form['comment_notes_after'] = '';
  /* コメントフォ＝ム見出しのタイトル */
  $form['title_reply'] = 'Leave a Reply';
  /*キャンセルリンクのテキスト*/
  $form['cancel_reply_link'] = '(or Cancel)';
  /* 送信ボタンのラベル */
  $form['label_submit'] = 'Post Comment';
  return $form;
}
```

・関数内で使う値を取得したり必須項目を知らせるメッセージを定義
・コメントフォームのtextareaタグのマークアップ。ここではコメントの文字列を入力している以外はデフォルトと同じ
・コメントの条件を要ログインにした場合のメッセージ（ディスカッション設定→ログインユーザーのみコメント）
・ログイン時に表示するメッセージ・省略
・コメント欄で使用できるタグを知らせるメッセージを空文字設定で削除
・コメントフォームの見出しのタイトル、送信ボタンのラベル→comment_formにパラメータを渡して設定することも
・返信をクリックした際のキャンセルリンク
・返信の際のコメントフォームの移動：header.phpに下記の記述がされていることが条件
`if ( is_singular() ) {
wp_enquene_script( 'comment-reply' )
}'`
・送信ボタン内のテキスト

###トラックバックURLを表示する
・WordPressブログ同士であれば、記事内にリンクを貼るだけで自動的にピンバックを送信することができる
→他のブログサービスからトラックバックを受け付けるには、トラックバックURLを表示して、読者に知らせる必要がある
・comment.phpのコメントフォームを出力している部分(comment_form();)を次のように変更
→トラックバック受付時のみという条件分岐を忘れずに

```lang:comments.php
<?php  // ここからコメントフォーム
  if(comments_open()):
    comment_form();
  else:
?>
  <p> 現在コメントは受け付けておりません。</p>
<?php endif; ?>
<?php if (pings_open()): ?>
  <h3 id="trackback-url">Trackback URL</h3>
  <p><input id="trackback_url" readonly="readonly" value="<?php trackback_url(true); ?>" type="text" onclick = "this.select();" /></p>
<?php else: ?>
  <p>現在トラックバックは受け付けておりません。</p>
<?php endif; ?>
```
・trackback_url(true/false)：トラックバックURLを取得／表示する　【ループ内】
→true:トラックバックURLを表示する　false:URLの取得のみ
→ここではreadonly属性をつけたinput要素のvalue属性の値として表示している

・コメントフォームの表示は、管理ページでの設定を受けて表示するため複雑な処理
→できるだけcomment_formを利用したカスタマイズを行うこと
・フィルターフック→CODEX


##ブログ用サイドバーのカスタマイズ
###いろいろな条件の記事をサイドバーに表示する
・p.159ではテンプレートタグwp_get_archivesを使って、最新記事を5件だけ表示した
→今度はサブループを使って、サイドバーに最新記事を3件表示する（サブループを作成して記事を取得すれば、特定のカテゴリーの記事やコメントの多い記事など、いろいろな条件を指定した記事の取得が可能）
・ウィジェットとカスタマイズしたサイドバーを同時に表示させる

・sidebar.phpの骨組み
`<div id="sidebar">
<?php 
オリジナルのサイドバーのためのコードを記述
if ( is_active_sidebar( 'sidebar-1' ) ) :
dynamic_sidebar( 'sidebar-1' );
endif;
?>
</div>`
→このようにウィジェットを同時に表示できたほうが、管理画面から簡単に表示を切り替えることもでき便利

・wp_get_archivesではなくサブループを使用することでアイキャッチ画像を表示させることもできグラフィカル
・サブループの作り方：WP_Queryを使う

```lang:sidebar.php
<div id="sidebar">

<div class="widget">
  <h2>Recent Posts</h2>

<?php $args = array( 'posts_per_page' => 3,); $my_query = new WP_Query($args);
  if ($my_query -> have_posts() ): ?>
  <ul id="sidebar-recent-posts" class="sidebar-posts">
  <?php while ($my_query -> have_posts()) : $my_query -> the_post(); ?>
    <li class="clearfix">
      <div class="sidebar-recent-posts-title">
        <h3><a href="<?php the_permalink() ?>"><?php the_title(); ?></a></h3>
        <p class="sidebar-date"><?php echo get_the_date(); ?></p>
        <p class="sidebar-comment-num"><?php comments_popup_link('Comment : 0', 'Comment : 1', 'Comments : %' ); ?></p>
      </div>

    <p class="siebar-thumbnail-box">
      <a href="<?php the_permalink() ?>" title="「<?php the_title(); ?>」の続きを読む">
  <?php if (has_post_thumbnail()) : the_post_thumbnail(array(75,75)); else: ?>
      <img src="<?php echo get_template_directory_uri(); ?>/images/noimage.gif" width="75" height="75" alt="" />
  <?php endif; ?>
      </a>
    </p>
    </li>
<?php endwhile; ?> 

<?php if ( is_active_sidebar( 'sidebar-1' ) ) : dynamic_sidebar( 'sidebar-1' ); endif; ?>
  </ul>
<?php endif; ?>
<?php wp_reset_postdata(); ?>
</div>

</div>
```
・WP_Queryに渡すパラメータを配列に代入
・アイキャッチがない場合の写真
・endwhileでループの終了
・＄argsに代入する要素を変更すれば、「特定のカテゴリー」の記事のみを表示(category_name)させたり、「表示させる順番」を変更(orderby)させることもできる

###コメントの多い記事を表示する
`$args = array('orderby' => 'comment_count');`

###タグクラウドを表示する
・タグの使用回数の多さをフォントサイズで表したもの
・専用のテンプレートタグを使えば簡単
→wp_tag_cloud(args)：タグクラウドを表示する
>パラメータの配列で指定できる主なインデックス
smallest:一番使用回数が少ないタグを表示するときのフォントサイズ
largest:一番使用回数が多いタグ〜
unit:フォントサイズの単位を指定。px,pt,em,%など
number:表示するタグの最大数。デフォルトでは45個。[０]で全てのタグを表示
format:フォーマットの指定。flatで半角スペース区切りのa要素、listでul要素-li要素。arrayとすると表示ではなく配列として値を返す
taxonomy:タグクラウドとして表示する分類の指定。post_tagでタグ、categoryでカテゴリーでも。自分で作成した分類も表示させることができる。
echo:タグクラウドを表示する場合true、取得のみはfalse

```lang:sidebar.php
<div class="widget">
  <h2>Tag Cloud</h2>
  <?php $args = array( 'smallest' => 14, 'largest' => 18, 'unit' => 'px', 'number' => 0, 'format' => 'flat', 'taxonomy' => 'post_tag', 'echo' => true ); ?>
  <p class = "tagcloud">
    <?php wp_tag_cloud($args); ?>
  </p>
</div>
```