【WordPress】カスタム投稿 + カスタムテンプレートフィールドで投稿機能を作る

今回WordPressのカスタム投稿タイプとカスタムテンプレートフィールドを使って投稿機能を実装してみたので
自分への備考録もかねて共有したいと思います。

WordPressのローカル開発はこちらにまとめたのでご参考まで
[超簡単にWordPressのローカル環境が構築できるLocalbyFlyheel
](https://docs.google.com/presentation/d/1x6MToUOpkJreVP4oFZx00fU4gNSZl3SxRTu9fLxtAy4/edit?usp=sharing)

# 対象
- [前提] WordPressの基本的な構築の仕方が分かってる方
- 自分だけのオリジナルブログを作りたい方
- クライアントに記事を編集してもらわないといけない案件

※WordPressの基本的な使い方は割愛します

## 用語説明

### カスタム投稿タイプとは
WordPressでは通常デフォルトで「投稿」と「固定ページ」が用意されています。
「投稿」のほうがユーザーに記事を書いてもらいページに動的に一覧表示させることができるのですが
デフォルトでは1ジャンルのため、新着情報、ブログ記事といった複数いろんなジャンルで投稿したい場合はこのままではできません。
そこで必要になるのがカスタム投稿タイプです。

### カスタムテンプレートフィールドとは
「投稿」や「カスタム投稿タイプ」で入力する際、テキストフィールドやラジオボタン、セレクトボックス、
ファイルアップロードなど、便利なUIを提供してくれるプラグインです。
[プラグインを入れる場合はこちらを参照](https://techacademy.jp/magazine/1384)

# 手順

### カスタム投稿タイプを使う
####functions.phpを編集
①add_actionで関数をフック
第2引数にカスタム投稿タイプの関数名
②関数名は任意（①と整合）
③投稿タイプ名の定義
ここで定義した値で表示させることができます
④表示する投稿タイプ名

```php
<?php

// カスタム投稿タイプの追加
add_action( 'init', 'create_post_type_1' ); // ①
function create_post_type_1() { // ②
    register_post_type( 'news', // ③
        [
            'labels' => [
                'name' => __( '新着情報' ), // ④
                'singular_name' => __( '新着情報' )
            ],
            'public' => true,
            'menu_position' => 5,
        ]
    );
}

// 2個目以降、関数名を変えて定義することが可能
add_action( 'init', 'create_post_type_2' );
function create_post_type_2() {
    register_post_type( 'blogs',
        [
            'labels' => [
                'name' => __( 'ブログ' ),
                'singular_name' => __( 'ブログ' )
            ],
            'public' => true,
            'menu_position' => 5,
        ]
    );
}

// 【おまけ】prev, nextリンクにスタイルを当てる関数
function add_prev_posts_link_class() {
    return 'class="prevLink"';
}
add_filter( 'previous_posts_link_attributes', 'add_prev_posts_link_class' );

function add_next_posts_link_class() {
    return 'class="nextLink"';
}
add_filter( 'next_posts_link_attributes', 'add_next_posts_link_class' );
```

保存すると投稿の下に新着情報が追加されました。
あとは投稿と同じように投稿可能です。

![スクリーンショット 2021-03-25 13.43.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/393193/b585ca58-38db-f520-f170-590f7c867a84.png)


### カスタムテンプレートフィールドを使う

まず、カスタムテンプレートフィールドのプラグインをインストール
インストール後、設定部分に項目が追加される。

![スクリーンショット 2021-03-25 13.46.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/393193/02aaaa48-8ee5-faab-a026-8d8c502e5777.png)

デフォルトでテンプレート（TEMPLATE #0）が入っているのでこちらを編集してもいいし、
TEMPLATE #1に新たにあるのでそちらに入力可能。

![スクリーンショット 2021-03-25 13.48.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/393193/8b1fc28c-28cd-3b13-7e46-c0be9bd6aed6.png)

◯テンプレートタイトル
選択する際の名称になります（わかりやすい名称にすることをお勧めします）

◯カスタムポストタイプ （カンマ区切り）
functions.phpで設定した③の値にしてください（ここではnews）

◯テンプレートコンテンツ
入力フォームのタイプ

```
[name]
type = text
size = 35
label = 店舗名
　
[genre]
type = checkbox
value = 和食 # 中華 # イタリアン # フレンチ
default = 和食 # イタリアン
label = ジャンル
　
[smoking]
type = radio
value = 禁煙 # 分煙 # 喫煙可
default = 
label = 禁煙・喫煙
　
[parking]
type = select
value = なし # あり（無料） # あり（有料）
default = あり（無料）
label = 駐車場
　
[impression]
type = textarea
rows = 4
cols = 40
tinyMCE = true
htmlEditor = true
mediaButton = true
label = お店の印象
　
[image1]
type = file
mediaPicker = true
mediaRemove = true
mediaLibrary = true
label = 店舗画像1

[image2]
type = file
mediaPicker = true
mediaRemove = true
mediaLibrary = true
label = 店舗画像2
```

```php
// コードではこれで出力できる
post_custom('name');
```

新規投稿を開いて、カスタムテンプレート内のセレクトボックスに
先ほど設定したnewsが出てくると思いますので、そちらをチェック。
チェックすると設定したフォームが出てきます。

![スクリーンショット 2021-03-25 13.58.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/393193/f94c2614-7ba5-36ac-c335-1aaa0d2164fc.png)

### コーディングする

```php
<?php
    $uri = get_theme_file_uri(); 

    $paged = get_query_var('paged') ? get_query_var('paged') : 1;
    $args = [
        'post_type' => 'news', // カスタム投稿名
        'paged' => $paged,
        'posts_per_page' => 1, // 表示する数
    ];
    $wp_query = new WP_Query($args);
?>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="<?=$uri;?>/css/style.css">
</head>
<body>
    <?php if ($wp_query->have_posts()): ?>
        <?php while ($wp_query->have_posts()): $wp_query->the_post(); ?>
            <h1><?php the_title(); ?></h1><!-- デフォルトタイトル部分 -->
            <p><?php the_content(); ?></p><!-- デフォルトコンテント部分 -->
            
            <!-- カスタムテンプレートフィールド -->
            <!-- テキスト -->
            <h3>店舗名</h3>
            <?php if ( post_custom('name') ): ?>
                <?=post_custom('name'); ?>
            <?php else: ?>
                入力されていません
            <?php endif; ?>

            <!-- チェックボックス -->
            <h3>ジャンル</h3>
            <?php if ( post_custom('genre') ): ?>
            <?php 
                if ( is_array( post_custom('genre') ) ) {
                    echo implode ( ", ", post_custom('genre') );
                } else {
                    echo post_custom('genre');
                }
            ?>
            <?php else: ?>
                選択されていません
            <?php endif; ?>

            <!-- ラジオボタン -->
            <h3>禁煙・喫煙</h3>
            <?php if ( post_custom('smoking') ): ?>
                <?=post_custom('smoking'); ?>
            <?php else: ?>
                選択されていません
            <?php endif; ?>

            <!-- セレクトボックス -->
            <h3>駐車場</h3>
            <?php if ( post_custom('parking') ): ?>
                <?=post_custom('parking'); ?>
            <?php else: ?>
                選択されていません
            <?php endif; ?>
            
            <!-- テキストエリア -->
            <h3>店舗印象</h3>
            <?php if ( post_custom('impression') ): ?>
                <?=post_custom('impression'); ?>
            <?php else: ?>
                入力されていません
            <?php endif; ?>

            <!-- 画像 -->
            <h3>画像1</h3>
            <?php if ( post_custom('image1') ): ?>
                <img src="<?=wp_get_attachment_image_src(post_custom('image1'),'full')[0]; ?>" alt="<?php the_title(); ?>" />
            <?php else: ?>
                画像がアップされていません
            <?php endif; ?>

            <h3>画像2</h3>
            <?php if ( post_custom('image2') ): ?>
                <img src="<?=wp_get_attachment_image_src(post_custom('image2'),'full')[0]; ?>" alt="<?php the_title(); ?>" />
            <?php else: ?>
                画像がアップされていません
            <?php endif; ?>
            <!-- カスタムテンプレートフィールド -->

            <p><?php the_time(get_option('date_format')); ?></p>
        <?php endwhile; ?>
    <?php else: ?>
        <p>まだ投稿がありません。</p>
    <?php endif; ?>

    <?php previous_posts_link('prev'); ?>

    <?php
        if ($wp_query->max_num_pages > 1) {
            $limitnum = 999999999;
            echo paginate_links(
                [
                    'base'         => str_replace($limitnum, '%#%', esc_url(get_pagenum_link($limitnum))),
                    'format'       => '',
                    'current'      => max(1, get_query_var('paged')),
                    'total'        => $wp_query->max_num_pages,
                    'prev_next'    => false,
                    'type'         => 'plain',
                ]
            );
        }
    ?>

    <?php next_posts_link('next'); ?>

    <?php wp_reset_postdata(); ?>

</body>
</html>
```

![スクリーンショット 2021-03-25 14.02.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/393193/38770acf-24fb-827e-12d8-64e8222a4604.png)

こんな感じに表示されました。
cssは与えてませんので各々ご用意お願いします。

# おまけ
nextとprevにアイコン付与させてみました。

```scss
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}
a {
    text-decoration: none;
    color: #333;
}
// currentクラスはactiveの場合自動で入る
.current {
    color: red;
}
.prevLink::before {
    content: "";
    display: inline-block;
    background-image: url("../img/prev.svg");
    background-size: contain;
    background-repeat: no-repeat;
    width: 20px;
    height: 20px;
    position: relative;
    right: 4px;
    top: 6px;
}
.nextLink::after {
    content: "";
    display: inline-block;
    background-image: url("../img/next.svg");
    background-size: contain;
    background-repeat: no-repeat;
    width: 20px;
    height: 20px;
    position: relative;
    left: 4px;
    top: 6px;
}
```
適当にアイコンを入れてください。
./img/next.svg
./img/prev.svg