WordPressでカスタム投稿タイプを作成し、HTMLに出力する

ワードプレスのテーマtwentytwentyを基盤に、オリジナルのカスタム投稿タイプを作成し、それをトップページの一覧画面にアーカイブ表示をする実装を行ったので、備忘録的にこの記事を残す。

# 環境情報

PHP：version 7.3.12
WordPress：version 5.5.3
WPテーマ：twentytwenty

# カスタム投稿タイプの作成

## 基盤の作成

投稿の種類にはお知らせや、製品紹介、スタッフ情報などサイトの目的やクライアントの要望によって様々だと思います。そのため要望や機能にあったカスタム投稿を追加する必要があります。

カスタム投稿を追加するには「functions.php」に下記のようば記述をしていきます。今回はイベント情報というカスタム投稿を追加してみます。

```functions.php
/*【管理画面】カスタム投稿を追加 */
/* 例）イベント情報を追加 */
function custom_post_type() {
    $labels = array(
        'name' => 'イベント情報', //管理画面に表示する名前
        'add_new' => '新規イベント追加', //新規追加ボタンの名前
        'add_new_item' => '新規イベントを追加', //新規追加ページのタイトル
        'edit_item' => 'イベントを編集', //編集ページのタイトル
        'new_item' => '新規イベント', //一覧ページの「新規追加」ボタンのラベル
        'view_item' => 'イベントを表示', //編集ページの「投稿を表示」ボタンのラベル
        'search_items' => 'イベントを検索', //一覧ページの検索ボタンのラベル
        'not_found' =>  '投稿されたイベントはありません', //一覧ページに投稿が見つからなかったときに表示
        'not_found_in_trash' => 'ゴミ箱にイベントはありません。', //ゴミ箱に何も入っていないときに表示
    );
    $args = array(
        'label' => __( 'Events' ),
        'labels' => $labels,
        'public' => true, //投稿タイプをパブリックにする
        'menu_position' => 4, //メニューに表示される順番
        'supports'=> array( 'title', 'thumbnail', 'excerpt', 'editor' ), //投稿できる内容,
        'menu_icon' => 'dashicons-flag', //アイコンの設定
        'has_archive' => 'event'
    );
    register_post_type( 'event', $args );
    // カテゴリー機能の追加
    register_taxonomy_for_object_type('category', 'event');
}
add_action( 'init', 'custom_post_type' );
```

<a href="https://www.webdesignleaves.com/pr/wp/wp_custom_post_type.html">第2パラメータ $args の引数（一部抜粋）</a>

![wp-add-event-post-1500x821.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/670866/ee278fc7-7948-ce01-fb6b-8cc6f3beee56.jpeg)
![wp-add-events-1500x822.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/670866/98a2b036-5d55-6204-4760-6808d70b6c2d.jpeg)
これでカスタム投稿のイベント情報が追加されました。

同じように新着情報や、スタッフ情報などのカスタム投稿を追加することができます。複数の投稿を追加するにはラベルを追加します。

## カスタム投稿のアイコンの変更

管理画面に表示させるアイコンは、WordPress公式のdashiconsから選択することができます。ラベルの「menu_icon」を編集してください。

```functions.php
'menu_icon' => 'ここにクラスを記述',//アイコンの設定
```

https://developer.wordpress.org/resource/dashicons/

## カスタム投稿ページのplaceholderの変更

次に投稿ページのカスタマイズをしていきます。まずは、タイトルのプレスホルダーを分かりやすい項目に変更しておきます。デフォルトではタイトルを追加になっていますが、今回はイベント名に変更します。

「functions.php」に以下のようなコードを追加します。

```functions.php
// playceholderの変更
function title_placeholder_change( $title ) {
    $screen = get_current_screen();
    if ( $screen->post_type == 'events' ) {
        $title = 'イベント名';
    }
    return $title;
}
add_filter( 'enter_title_here', 'title_placeholder_change' );
```

「$title = ”;」の部分に変更したい文字を入れます。
![wp-edit-placeholder-1500x821.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/670866/4c1b0a89-135f-ea9f-f87f-7ae40e5bc821.jpeg)
![wp-edit-placeholder2-1500x821.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/670866/e384ef66-68d5-a09b-ce25-17222f9a53f1.jpeg)
これで「タイトル名」から「イベント名」に変更となりました。

## カスタム投稿に入力エリアを追加

次に先ほど追加したカスタム投稿に任意の入力エリアを追加します。

例としてイベント情報にイベント期間を入力する欄を設けます。「functions.php」に追記していきましょう。

```functions.php
// 固定カスタムフィールドボックス
function add_event_fields() {
    add_meta_box( 'event_setting', 'イベントの情報', 'insert_event_fields', 'events', 'normal' );
}
add_action( 'admin_menu', 'add_event_fields' );

// カスタムフィールドの入力エリア
function insert_event_fields() {
    global $post;
    //下記に管理画面に表示される入力エリアを作ります。「get_post_meta()」は現在入力されている値を表示するための記述です。
    echo '期間： <input type="text" name="event_date" placeholder="例)4/21~5/21" value="'.get_post_meta( $post->ID, 'event_date', true ).'" size="50"><br>';
}
```

```php
add_meta_box( $id, $title, $callback, $screen, $context, $priority, $callback_args );
```

<dl>
  <dt>$id</dt>
  <dd>（文字列） （必須） 編集画面セクションの HTML ID
  <dd>初期値： なし</dd>
  <dt>$title</dt>
  <dd>（文字列） （必須） 編集画面セクションのタイトル、画面上に表示される</dd>
  <dd>初期値： なし</dd>
  <dt>$callback</dt>
  <dd>（callback） （必須） 編集画面セクションに HTML 出力する関数. The function name as a string, or, within a class, an array to call one of the class's methods. The callback can accept up to two arguments: the first argument is the $post object for the post or page that is currently being edited. The second argument is the full metabox item (an array), see Callback args. See the second example under Examples below.</dd>
  <dd>初期値： なし</dd>
  <dt>$screen</dt>
  <dd>（文字列） （オプション） The type of writing screen on which to show the edit screen section (examples include 'post','page','dashboard','link','attachment','custom_post_type','comment' where custom_post_type is the custom post type slug)</dd>
  <dd>初期値： null</dd>
  <dt>$context</dt>
  <dd>（文字列） （オプション） 編集画面セクションが表示される部分 ('normal', 'advanced' または (2.7 以降) 'side')</dd>
  <dd>初期値： 'advanced'</dd>
  <dt>$priority</dt>
  <dd>（文字列） （オプション） ボックスが表示される優先度 ('high', 'core', 'default' または 'low')</dd>
  <dd>初期値： 'default'</dd>
  <dt>$callback_args</dt>
  <dd>（array） （オプション） Arguments to pass into your callback function. The callback will receive the $post object and whatever parameters are passed through this variable.</dd>
  <dd>初期値： null</dd>
</dl>
![wp-add-inputarea-1500x821.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/670866/6bb58bc1-e76b-c36b-f459-5ea8d4293f2e.jpeg)
これでカスタム投稿ページにイベント期間を入力する項目が追加されました。

## カスタム投稿に入力内容を保存

入力するエリアは追加されましたが、入力した値を保存しないといけないのでそのコードを記述します。

```functions.php
// カスタムフィールドの値を保存
function save_event_fields( $post_id ) {
    if ( ! empty( $_POST['event_date'] ) ) {
        update_post_meta( $post_id, 'event_date', $_POST['event_date'] ); //値を保存
    } else {
        delete_post_meta( $post_id, 'event_date' ); //値を削除
    }
}
add_action( 'save_post', 'save_event_fields' );
```

これでカスタム投稿ページにイベント情報・期間の入力エリアが表示され、入力された値を使用することができます。

## カスタム投稿一覧ページのレイアウトを変更

カスタム投稿ページで新規にページを追加します。
すると一覧ページは下記のような表示になると思います
![wp-events-default-1500x822.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/670866/bd27f9bd-e606-062a-454c-67c238928263.jpeg)
せっかくなので先ほど追加した、イベント期間とアイキャッチをイベント情報一覧ページで表示させます。

```functions.php
// イベント期間とアイキャッチの表示
function manage_events_posts_columns( $columns ) {
    $columns = array(
        'cb' => '<input type="checkbox" />',
        'title' => 'タイトル',
        'thumbnail' => 'アイキャッチ',
        'event_date' => '期間'
        'categories' => 'カテゴリー',
        'tags' => 'タグ',
        'comments' => '<div class="comment-grey-bubble" title="コメント"></div>',
        'date' => '作成日',
        'modified' => '更新日',
    );
    return $columns;
}

function add_column( $column_name, $post_id ) {
    if ( $column_name == 'event_date' ) {
        $date = get_post_meta( $post_id, 'event_date', true );
    }
    if ( isset( $date ) && $date ) {
        echo ( $date );
    }

    if ( 'thumbnail' == $column_name ) {
        $thum = get_the_post_thumbnail( $post_id, 'small', array( 'style'=>'width:100px;height:auto;' ) );
    }
    if ( isset( $thum ) && $thum ) {
        echo $thum;
    } else {
        echo __( 'None' );
    }

    // 最終更新日
    if ( $column_name == 'modified' ) {
        $modified_date = the_modified_date( 'Y年Md日 g:i A' );
    }
    if ( isset( $modified_date ) && $modified_date ) {
        echo $modified_date;
    }
}

add_filter( 'manage_edit-events_columns', 'manage_events_posts_columns' );
add_action( 'manage_events_posts_custom_column', 'add_column_to_events', 10, 2 );

// 管理画面のソート機能に最終更新日を追加
function my_manage_edit_events_sortable_columns( $columns ) {
    $columns['modified'] = 'modified';
    return $columns;
}
add_filter( 'manage_edit-events_sortable_columns', 'my_manage_edit_events_sortable_columns' );

// 管理画面のカラムの幅を調整
function colwidth_css(){
    ?>
    <style>
        th#modified {
            width: 14%;
        }
    </style>
    <?php
}
add_action('admin_head','colwidth_css');
```

![wp-edit-events-1500x822.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/670866/7b16392a-77fa-d48e-9916-174d93ce8cb7.jpeg)
これで入力したイベント期間と設定したアイキャッチが一覧ページに表示されました。

# HTMLに出力する

先ほど作成したカスタム投稿タイプを、トップページで表示するという例です。

経験上、メインループに影響を与えないサブループ（カスタムループ）で記述しておくほうが安全ですね。

## get_posts( )

サブループの記述方法には、「WP_Query( )」と「get_posts( )」がありますが、「WP_Query()」の方がより複雑な処理を行うことができます。

初心者の方には「get_posts( )」の方が優しいので、今回はこちらを使った実装を紹介します。

```index.php
<ul>
 
  <?php
    $event_args = [
      'post_type' => 'event', // カスタム投稿名が「event」の場合
      'posts_per_page' => 5, // 表示する数
    ];
    $event_posts = get_posts( $event_args ); ?>
 
  <?php if ( $event_posts ) : foreach ( $event_posts as $post ) : setup_postdata( $post ); // 投稿がある場合 ?>
 
    <!-- ▽ ループ開始 ▽ -->
 
    <li>
      <p><?php the_time( 'Y年 n月' ); ?></p>
      <h3><?php the_title( ); ?></h3>
      <?php the_content( ); ?>
    </li>
 
    <!-- △ ループ終了 △ -->
 
  <?php endforeach; ?>
 
  <?php else : // 記事がない場合 ?>
 
    <li>まだ投稿がありません。</li>
 
  <?php endif; wp_reset_postdata( ); ?>
 
</ul>
```

<a href="https://www.webdesignleaves.com/pr/wp/wp_func_loop.html">ループで使うテンプレートタグや関数</a>

get_posts( ) を使うことで、サブクエリを発行することができ、任意のデータを表示することができるようになり、ループ処理の中でテンプレートタグや関数が使えるようになります。

get_posts( ) でのループ処理が一通り終わったタイミングで  wp_reset_postdata( ) でメインクエリにリセットすることを忘れないようにしましょう。

## カスタム投稿の入力内容を表示させる

### 入力欄を自作した場合

さきほどカスタム投稿のイベント情報に、期間を入力する欄を設けましたが、ここに入力された値をフロントで表示させるには下記のコードを使用します。

```index.php
<?php echo get_post_meta($post->ID, 'event_date', true); ?>
```

### プラグインAdvanced Custom Fields（ ACF ）を使って入力欄を作成した場合

中身をそのまま表示させたい場合とそうでない場合で表現が異なります。

```php
// そのまま表示させたい場合
the_field( 'event_date' );

// 表示させない場合
get_field( 'event_date' );
```

## the_content( ) のpタグを外す

the_content( ) はデフォルトでpタグで囲まれるようになっています。

しかし、場合によってはpタグで囲みたくないこともあります。そんなときは remove_filter( ) 関数を使います。

```index.php
<?php
    remove_filter( 'the_content', 'wpautop' );
    the_content( );
?>
```

Pタグで囲みたくないコンテントが出力されている場所「the_content( )」を探します。
見つけたら the_content( ) の前に remove_filter( 'the_content', 'wpautop' ) を記述し、the_content を wpautop フィルターフック から外してやる。

# カテゴリーとタグを使えるようにする

もし作成したカスタム投稿タイプでタグやカテゴリーを使えるようにしたい場合は、register_post_type() の下に以下を追記する。

```functions.php
    .
    .
    .
    register_post_type( 'event', $args );

    register_taxonomy_for_object_type('category', 'event');
    register_taxonomy_for_object_type('post_tag', 'event');
}
add_action( 'init', 'custom_post_type' );
```