さぁ!検索しよう!

ECサイトの仕組みが知りたい&WordPressでプラグインを利用せずにECサイトのCMSを構築してみたいと思い、このような記事を書くに至りました。

前回に続いて第2回は、カート機能を実装する方法です。

尚、index.phpやsingle.php等のテンプレートは既に用意されているものとします。

フォームを作成する

始めに第1回で作成した商品ページのコンテンツ部分のテンプレートcontent.phpにフォームを追加し、数量と商品データをカートページに送れるようにします。

content.php

<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
    <div class="entry-content mb-5">
        <?php
            $price = get_post_meta($post->ID, 'price', true);
            $stock = get_post_meta($post->ID, 'stock', true);
            $description = get_post_meta($post->ID, 'description', true);
            $image = get_post_meta($post->ID, 'image', true);
        ?>
        <div class="row">
            <div class="col-lg-7">
                <div class="main-image embed-responsive embed-responsive-16by9 bg-light mb-3">
                    <?php echo wp_get_attachment_image($images[0], 'full', false, array('class' => 'embed-responsive-item')); ?>
                </div>
            </div>
            <div class="col-lg-5">
                <?php the_title( '<h1 class="product-name mt-0 mb-3">', '</h1>' ); ?>
                <dl class="product-price d-flex font-weight-bold mb-3">
                    <dt class="text-danger">¥</dt>
                    <dd class="text-danger">
                        <?php echo number_format(esc_html($price)); ?>
                    </dd>
                </dl>
                <div class="product-stock mb-3">
                <?php if($stock == 0): ?>
                    <strong class="text-danger">在庫なし</strong>
                <?php elseif($stock < 10): ?>
                    <strong class="text-warning">残り<?php echo esc_html($stock) ?>点</strong>
                <?php else: ?>
                    <strong class="text-success">在庫あり</strong>
                <?php endif; ?>
                </div>
                <div class="product-description">
                <?php echo esc_html($description) ?>
                </div>
            </div>
        </div>
        <form action="<?php echo esc_url( home_url('/cart')); ?>" method='post'>
            <input type="hidden" name="postid" value="<?php echo $post->ID; ?>">
            <input type="hidden" name="stock" value="<?php echo esc_attr($stock); ?>">
            <input type="hidden" name="pname" value="<?php echo esc_attr(get_the_title()); ?>">
            <input type="hidden" name="price" value="<?php echo esc_attr($price); ?>">
            <input type="hidden" name="description" value="<?php echo esc_attr($description); ?>">
            <input type="hidden" name="image" value="<?php echo esc_attr($image[0]); ?>">
            <?php
                if($stock > 0):
            ?>
            <label>個数:</label>
            <select name="num" class="mb-3 form-control d-inline-block w-auto">
            <?php
                for($i = 1; $i <= $stock; $i++):
            ?>
                <option value="<?php echo esc_attr($i); ?>"><?php echo esc_html($i); ?>個</option>
            <?php
                endfor;
            ?>
            </select><br>
            <input type="submit" name="submit" class="btn btn-primary" value="カートに入れる">
            <?php
                else:
            ?>
            <input type="submit" name="submit" class="btn btn-primary" value="完売しました" disabled>
            <?php
                endif;
            ?>
        </form>
    </div><!-- .entry-content -->
</article><!-- #post-## -->

商品データと数量はカートページに送るので、フォームのaction属性にはカートページのURLを指定します。

数量はselect要素で在庫の分だけ選択できるようにします。商品データのフォームは必要としないのでinput[type="hidden"]で送ります。

これで、数量を選択してカートに入れるボタンを押すとカートページへ遷移します。

セッションを開始する

カートに入れた商品はどのページからでも確認できるようにセッション変数に保存します。そのためセッションを開始します。

functions.phpに以下のコードを書きます。

functions.php

add_action('init', 'session_start_callback');
function session_start_callback(){
    session_start();
}

アクションフックinitで、サイトが表示されたときにsession_start()が実行されてセッションが開始されるようにします。

データベースでは、カートに入れた商品を一定時間が経過したときに自然に削除することができないため、セッションを用います。

カートページを作成する

カートページを作成して、商品ページから送られてきた商品データと数量、つまりカートに入れた商品を受け取って一覧表示します。

cart.phpを作成する

始めにカートページのテンプレートcart.phpを作成します。

cart.php

<?php
/*
Template Name: cart
*/
?>

<?php get_header(); ?>

    <div id="primary" class="content-area">
        <main id="main" class="site-main" role="main">

        <?php
        // Start the loop.
        while ( have_posts() ) : the_post();

            // Include the page content template.
            get_template_part( 'content', 'cart' );


        // End the loop.
        endwhile;
        ?>

        </main><!-- .site-main -->
    </div><!-- .content-area -->

<?php get_footer(); ?>

先頭に「Template Name: cart」とコメントアウトすることで、cart.phpが固定ページ作成時にテンプレートとして認識されます。

cart.phpのコンテンツ部分はcontent-cart.phpとして別に作成し、get_template_part()でループ内でインクルードします。

content-cart.phpを作成する

そして、cart.phpのコンテンツ部分content-cart.phpを作成します。

content-cart.php

<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
    <header class="entry-header">
        <?php the_title( '<h1 class="entry-title">', '</h1>' ); ?>
    </header><!-- .entry-header -->
    <div class="entry-content">
<?php
$c_user = wp_get_current_user();
$c_id = $c_user->ID;
$sum = 0;
$row = array();
if(!isset($_SESSION['cart'])) $_SESSION['cart'] = array();
if(!isset($_SESSION['rows'])) $_SESSION['rows'] = array();
if(!isset($_SESSION['num'])) $_SESSION['num'] = array();
if(!isset($_SESSION['price'])) $_SESSION['price'] = array();
if(!isset($_SESSION['stock'])) $_SESSION['stock'] = array();
if(!isset($_SESSION['postid'])) $_SESSION['postid'] = array();
if(!isset($_SESSION['sum'])) $_SESSION['sum'] = 0;
if(!isset($_SESSION['image'])) $_SESSION['image'] = array();
if(!isset($_SESSION['pname'])) $_SESSION['pname'] = array();

if(@$_POST['submit']) {
    @$_SESSION['num'][$_POST['pname']] += $_POST['num'];
    $_SESSION['price'][$_POST['pname']] = $_POST['price'];
    $_SESSION['cart'][$_POST['pname']] = $_SESSION['num'][$_POST['pname']] * $_SESSION['price'][$_POST['pname']];//小計
    @$_SESSION['image'][$_POST['pname']] = $_POST['image'];

    $row = array('image' => $_SESSION['image'][$_POST['pname']], 'name' => $_POST['pname'], 'price' => $_SESSION['price'][$_POST['pname']], 'num' => $_SESSION['num'][$_POST['pname']]);

    $_SESSION['rows'][$_POST['pname']] = $row; 
    $_SESSION['stock'][$_POST['pname']] = $_POST['stock'] - $_SESSION['num'][$_POST['pname']];

    $_SESSION['postid'][$_POST['pname']] = $_POST['postid'];

    foreach($_SESSION['postid'] as $key => $val) {
        update_post_meta($val, 'order_num', $_SESSION['num'][$key]);
        update_post_meta($val, 'order_id', $_SESSION['postid'][$key]);
    }

    update_post_meta($_SESSION['postid'][$_POST['pname']], 'stock', $_SESSION['stock'][$_POST['pname']]);
}

if(!empty($_SESSION['cart'])) {
    foreach($_SESSION['cart'] as $name) {
        $s += $name;
        $_SESSION['sum'] = $s;
    }
}
?>
<?php if($_SESSION['sum']) { ?>
    <h2 class="mb-4">カートに以下の商品を入れました。</h2>
    <table class="cart-info table">
        <thead>
            <tr>
                <th scope="col"></th><th scope="col">商品名</th><th scope="col">価格</th><th scope="col">数量</th><th scope="col"></th>
            </tr>
        </thead>
            <?php foreach($_SESSION['rows'] as $key => $row) { ?>
                <?php if(!empty($row)) { ?>
                    <tr>
                        <?php foreach($row as $rkey => $value) { ?>
                            <?php if($rkey === 'image'): ?>
                                <td class="text-center">
                                    <?php echo wp_get_attachment_image($value, 'thumbnail'); ?>
                                </td>
                            <?php elseif($rkey === 'name'): ?>
                                <td class="align-middle">
                                    <a href="<?php the_permalink($_SESSION['postid'][$value]); ?>"><?php echo $value; ?></a>
                                </td>
                            <?php elseif($rkey === 'price'): ?>
                                <td class="align-middle">
                                    ¥<?php echo number_format($value); ?>
                                </td>
                            <?php endif; ?>
                        <?php } ?>
                        <?php foreach($_SESSION['num'] as $nkey => $nvalue) { ?>
                        <?php if($nkey == $key) { ?>
                        <td class="align-middle">
                            <div class="d-flex align-items-center">
                                <button>
                                    <a href="<?php echo esc_url( home_url( '/' ). "reduce?code=$nkey") ?>">-</a>
                                </button>
                                <span class="mx-2">
                                    <?php echo $nvalue; ?>
                                </span>
                                <?php if($_SESSION['stock'][$nkey] <= 0): ?>
                                    <button disabled>+</button>
                                <?php else: ?>
                                    <button>
                                        <a href="<?php echo esc_url( home_url( '/' ). "gain?code=$nkey") ?>">+</a>
                                    </button>
                                <?php endif; ?>
                            </div>
                        </td>
                        <?php } ?>
                        <?php } ?>
                        <td class="align-middle"><a href="<?php echo esc_url( home_url( '/' ). "delete?code=$key") ?>">削除</a></td>
                    </tr>

                <?php } ?>
            <?php } ?>
        <tr><td colspan="3"></td><th>商品合計</th><td>¥<?php echo number_format($_SESSION['sum']); ?></td></tr>
    </table>
    <?php } else {  ?>
    <h2>カートの中身は空です。</h2>
<?php } ?>

解説

変数・配列の初期化

始めに変数や配列の初期化を行います。

$row = array();
if(!isset($_SESSION['cart'])) $_SESSION['cart'] = array();
if(!isset($_SESSION['rows'])) $_SESSION['rows'] = array();
if(!isset($_SESSION['num'])) $_SESSION['num'] = array();
if(!isset($_SESSION['price'])) $_SESSION['price'] = array();
if(!isset($_SESSION['stock'])) $_SESSION['stock'] = array();
if(!isset($_SESSION['postid'])) $_SESSION['postid'] = array();
if(!isset($_SESSION['sum'])) $_SESSION['sum'] = 0;
if(!isset($_SESSION['image'])) $_SESSION['image'] = array();
if(!isset($_SESSION['pname'])) $_SESSION['pname'] = array();

$row配列には、商品画像・商品名・価格・数量をforeach文で横一行に表示するために格納します。

セッション変数$_SESSION['sum']にはカートに入れた商品の合計金額が入ります。何もセットされていないときのみ0を代入します。

それ以外のセッション変数には商品別に送られてきたデータが入ります。何もセットされていないときのみ空の配列をセットします。
例えば、セッション変数$_SESSION['cart']は商品別の合計を格納する配列です。セッション変数$_SESSION['rows']は商品別の$rowを格納する配列です。

送られてきたデータを商品別に受け取る

次に商品ページから送られてきたデータを先程のセッション変数へ商品別に代入します。

if(@$_POST['submit']) {
    @$_SESSION['num'][$_POST['pname']] += $_POST['num'];
    $_SESSION['price'][$_POST['pname']] = $_POST['price'];
    $_SESSION['cart'][$_POST['pname']] = $_SESSION['num'][$_POST['pname']] * $_SESSION['price'][$_POST['pname']];//小計
    @$_SESSION['image'][$_POST['pname']] = $_POST['image'];

    $row = array('image' => $_SESSION['image'][$_POST['pname']], 'name' => $_POST['pname'], 'price' => $_SESSION['price'][$_POST['pname']], 'num' => $_SESSION['num'][$_POST['pname']]);

    $_SESSION['rows'][$_POST['pname']] = $row; 
    $_SESSION['stock'][$_POST['pname']] = $_POST['stock'] - $_SESSION['num'][$_POST['pname']];//$_POST['stock'] - $_POST['num'];

    $_SESSION['postid'][$_POST['pname']] = $_POST['postid'];

    foreach($_SESSION['postid'] as $key => $val) {
        update_post_meta($val, 'order_num', $_SESSION['num'][$key]);
        update_post_meta($val, 'order_id', $_SESSION['postid'][$key]);
    }

    update_post_meta($_SESSION['postid'][$_POST['pname']], 'stock', $_SESSION['stock'][$_POST['pname']]);
}

各セッション変数の2つ目のキーを送られてきた商品名$_POST['pname']にしていますが、これはどの商品のデータであるかを示すためです。
$_POST['pname']がカレーであれば$_SESSION['image']['カレー']でカレーの画像ということになります。

数量$_SESSION['num']は商品別に加算していきます。そうでないと代入される度にリセットされますから。。

商品別の合計金額$_SESSION['cart']には、送られてきた(カートに入った)商品の数量$_SESSION['num']×価格$_SESSION['price']で商品別の合計金額を代入します。

$rowには送られてきたデータから商品画像、商品名、価格、数量を順にセットし、それを$_SESSION['rows']に代入します。

カートに入れた商品の在庫$_SESSION['stock'][$_POST['pname']]には、カートに入れた商品の数$_SESSION['num'][$_POST['pname']]を差し引いた残りの在庫数を代入します。

カートに入れた商品のID$_SESSION['postid'][$_POST['pname']]は、カートページに表示する商品名のパーマリンクを設定する際等に必要となります。

また、カートに商品を入れる度にカートに入れた商品の注文数とIDをupdate_post_meta()で商品ページ毎にデータベース(カスタムフィールド)に保存します。

何故データベースなのか。それはセッション変数に保存してしまうと、時間の経過やブラウザの履歴を削除することによってCOOKIEが削除されます。
それによってセッションが切れてセッション変数の中身が全て消えてしまうことで、カートに入れた商品は全て消えます。

つまり、このままではカートに入れた商品は消えて在庫数は減ったままという状態になってしまいます。なのでデータベースに保存しておく必要があるのです。

合計金額を算出する

次にカートに入れた商品の合計金額を算出します。

if(!empty($_SESSION['cart'])) {
    foreach($_SESSION['cart'] as $name) {
        $s += $name;
        $_SESSION['sum'] = $s;
    }
}

商品別の合計金額$_SESSION['cart']['pname']を全て足し合わせることで、カートに入れた全商品の合計金額$_SESSION['sum']を求めます。

これでカートページにカートに入れた商品を一覧表示する準備ができました。

カートに入れた商品を一覧表示する

最後にカートに入れた全商品データを基に、カートに入れた商品を一覧表示してカートページを完成させます。

<?php if($_SESSION['sum']) { ?>
    <h2 class="mb-4">カートに以下の商品を入れました。</h2>
    <table class="cart-info table">
        <thead>
            <tr>
                <th scope="col"></th><th scope="col">商品名</th><th scope="col">価格</th><th scope="col">数量</th><th scope="col"></th>
            </tr>
        </thead>
            <?php foreach($_SESSION['rows'] as $key => $row) { ?>
                <?php if(!empty($row)) { ?>
                    <tr>
                        <?php foreach($row as $rkey => $value) { ?>
                            <?php if($rkey === 'image'): ?>
                                <td class="text-center">
                                    <?php echo wp_get_attachment_image($value, 'thumbnail'); ?>
                                </td>
                            <?php elseif($rkey === 'name'): ?>
                                <td class="align-middle">
                                    <a href="<?php the_permalink($_SESSION['postid'][$value]); ?>"><?php echo $value; ?></a>
                                </td>
                            <?php elseif($rkey === 'price'): ?>
                                <td class="align-middle">
                                    ¥<?php echo number_format($value); ?>
                                </td>
                            <?php endif; ?>
                        <?php } ?>
                        <?php foreach($_SESSION['num'] as $nkey => $nvalue) { ?>
                        <?php if($nkey == $key) { ?>
                        <td class="align-middle">
                            <div class="d-flex align-items-center">
                                <button>
                                    <a href="<?php echo esc_url( home_url( '/' ). "reduce?code=$nkey") ?>">-</a>
                                </button>
                                <span class="mx-2">
                                    <?php echo $nvalue; ?>
                                </span>
                                <?php if($_SESSION['stock'][$nkey] <= 0): ?>
                                    <button disabled>+</button>
                                <?php else: ?>
                                    <button>
                                        <a href="<?php echo esc_url( home_url( '/' ). "gain?code=$nkey") ?>">+</a>
                                    </button>
                                <?php endif; ?>
                            </div>
                        </td>
                        <?php } ?>
                        <?php } ?>
                        <td class="align-middle"><a href="<?php echo esc_url( home_url( '/' ). "delete?code=$key") ?>">削除</a></td>
                    </tr>

                <?php } ?>
            <?php } ?>
        <tr><td colspan="3"></td><th>商品合計</th><td>¥<?php echo number_format($_SESSION['sum']); ?></td></tr>
    </table>
    <?php } else {  ?>
    <h2>カートの中身は空です。</h2>
<?php } ?>

レイアウトはテーブル要素で行います。

合計金額$_SESSION['sum']が0円ではなければ表示します。
反対に0円だったときは「カートの中身は空です。」と表示します。

$_SESSION['rows]配列から商品毎のデータの集まりである$rowを取り出し、更に$rowからforeach文で商品データを取り出してtd要素に出力していき、表を埋めていきます。

商品画像はwp_get_attachment_image()$rkey = imageであるときの$value = IDを渡してimg要素を出力します。

商品名の出力の際は、a要素でリンク先をthe_permalink()で指定します。the_permalink()の引数を商品ページのID$_SESSION['postid'][$value]とすることで、リンク先を商品ページにします。

価格の出力は、価格ですのでnumber_format()で数値を3桁のカンマ区切で出力します。

数量を変更できる機能を実装する

数量は、ただ出力するだけではなく数量の両端に「-」と「+」のボタンを表示して数量を変更できる機能を実装します。

「-」ボタンのリンクはhttp://[ドメイン名]/reduce?code=[商品名]であり、ボタンを押すとこのページに遷移します。reduceはreduce.phpのことで、このページのテンプレートであり、ページは固定ページで作成します。

そしてreduce.phpは?code=[商品名]によって$_GET[‘code’] = [商品名]を受け取ります。

reduce.phpは以下のようにして作成します。

reduce.php

<?php
/*
Template Name: reduce
*/
?>
<?php
$_SESSION['num'][$_GET['code']]--;
$_SESSION['stock'][$_GET['code']]++;

update_post_meta($_SESSION['postid'][$_GET['code']], 'stock', $_SESSION['stock'][$_GET['code']]);

update_post_meta($_SESSION['postid'][$_GET['code']], 'order_num', $_SESSION['num'][$_GET['code']]);

$_SESSION['cart'][$_GET['code']] = $_SESSION['num'][$_GET['code']] * $_SESSION['price'][$_GET['code']];

if($_SESSION['num'][$_GET['code']] <= 0) {
    $_SESSION['rows'][$_GET['code']] = null;
    $_SESSION['cart'][$_GET['code']] = null;
    $_SESSION['num'][$_GET['code']] = null;
    $_SESSION['image'][$_GET['code']] = null;

    delete_post_meta($_SESSION['postid'][$_GET['code']], 'order_num', $_SESSION['num'][$_GET['code']]);
    delete_post_meta($_SESSION['postid'][$_GET['code']], 'order_id', $_SESSION['postid'][$_GET['code']]);

    $_SESSION['postid'][$_GET['code']] = null;
}

header('Location:' .esc_url( home_url('/')). 'cart');
?>

先頭に「Template Name: reduce」とコメントアウトし、固定ページにテンプレートとして認識されるようにします。

reduce.phpではこの受け取った商品名の数量を一つ減らし、減らしたので在庫数を一つ増やす処理を行い、update_post_meta()でカスタムフィールドstockの更新も行います。

また、減らした商品の合計を再計算します。

「-」ボタンを押して数量が0になった場合、セッション変数にnullを代入してカートの中身を空にします。更にdelete_post_meta()で数量が0になった商品の注文数とIDのカスタムフィールド(order_num, order_id)の値を削除します。

最後にheader()でcart.phpに戻るようします。

ただ、reduce.phpはテンプレートであってページではなのでURLを持っておらず、このままでは「-」ボタンを押しても何も起こりません。ページにするには、固定ページを作成してテンプレートとして先ほど作成したreduce.phpを組み込み、URLを設定する必要があります。
なので、固定ページを新規作成します。

固定ページのタイトルですが、reduce.phpはheader()によって一瞬でカートページに戻り表示されることはないため、テンプレート名と同じreduceとしています。

テンプレートは先ほど作成したreduceを選択します。

パーマリンクはテンプレート名と同じreduceとします。

これで公開するとページが作成されて「-」ボタンが機能します。

reduce.phpと同様に「+」ボタンのリンク先のページテンプレートとなるgain.phpも作成します。

gain.php

<?php
/*
Template Name: gain
*/
?>
<?php
$_SESSION['num'][$_GET['code']]++;
$_SESSION['stock'][$_GET['code']]--;

update_post_meta($_SESSION['postid'][$_GET['code']], 'stock', $_SESSION['stock'][$_GET['code']]);

update_post_meta($_SESSION['postid'][$_GET['code']], 'order_num', $_SESSION['num'][$_GET['code']]);

$_SESSION['cart'][$_GET['code']] = $_SESSION['num'][$_GET['code']] * $_SESSION['price'][$_GET['code']];

header('Location:' .esc_url( home_url('/')). 'cart');
?>

先頭に「Template Name: gain」とコメントアウトし、固定ページにテンプレートとして認識されるようにします。

「+」ボタンを押したときに数量を一つ増やして在庫数を一つ減らし、update_post_meta()でカスタムフィールドの値の更新も行います。

そして増やした商品の合計を再計算し、header()でカートページに戻ります。

gain.phpに関してもreduce.phpのときと同様に、固定ページでページを作成します。

これで「+」ボタンが機能します。

「+」ボタンは在庫数が0以下になると、無効化した「+」ボタンに切り替えます。

商品を削除する機能を実装する

表示した各商品の右端に削除ボタンを設置します。

削除ボタンのリンクはhttp://[ドメイン名]/delete?code=[商品名]とするため、delete.phpを作成してここに選択した商品の削除処理を行います。

delete.php

<?php
/*
Template Name: delete
*/
?>
<?php
$_SESSION['stock'][$_GET['code']] = $_SESSION['stock'][$_GET['code']] + $_SESSION['num'][$_GET['code']];
update_post_meta($_SESSION['postid'][$_GET['code']], 'stock', $_SESSION['stock'][$_GET['code']]);

delete_post_meta($_SESSION['postid'][$_GET['code']], 'order_num', $_SESSION['num'][$_GET['code']]);

delete_post_meta($_SESSION['postid'][$_GET['code']], 'order_id', $_SESSION['postid'][$_GET['code']]);

$_SESSION['rows'][$_GET['code']] = null;
$_SESSION['cart'][$_GET['code']] = null;
$_SESSION['num'][$_GET['code']] = null;
$_SESSION['image'][$_GET['code']] = null;

$_SESSION['postid'][$_GET['code']] = null;

header('Location: '.esc_url( home_url('/')). 'cart');
?>

削除した商品の数$_SESSION['num'][$_GET['code']]を現在の在庫数$_SESSION['stock'][$_GET['code']]に加えて、カートに入れる前の在庫数に戻します。update_post_meta()でデータベースの上書きも行います。

delete_post_meta()で削除した商品の注文数とIDをデータベースから削除します。

削除した商品のデータの集まり$_SESSION['rows'][$_GET['code']]と合計、数量、画像、そしてIDのセッション変数にnullを代入します。これによってheader()でcart.phpに戻ったときには削除した商品が表から消えているはずです。

最後に固定ページでdelete.phpをテンプレートに選択したページを作成します。これで削除ボタンが機能します。

合計金額を出力する

表の下に商品の合計金額を出力します。また、金額はnumber_format()で3桁のカンマ区切りにします。

一覧はこれで完成です。

カートを空にするボタンを設置する

ページ下にカートを空にするボタンを設置します。

カートを空にするボタンのリンク先はhttp://[ドメイン名]/emptyとするため、始めにempty.phpを作成し、カートを空にする処理を行います。

empty.phpは以下のようにして作成します。

empty.php

<?php
/*
Template Name: empty
*/
?>
<?php
    foreach($_SESSION['stock'] as $key => $value) {
        $_SESSION['stock'][$key] = $value + $_SESSION['num'][$key];
        update_post_meta($_SESSION['postid'][$key], 'stock', $_SESSION['stock'][$key]);
    }

    foreach($_SESSION['postid'] as $key => $value) {
        delete_post_meta($value, 'order_num');
        delete_post_meta($value, 'order_id');
    }

    $_SESSION['cart'] = null;
    $_SESSION['rows'] = null;
    $_SESSION['num'] = null;

    $_SESSION['price'] = null;
    $_SESSION['stock'] = null;
    $_SESSION['postid'] = null;
    $_SESSION['image'] = null;

    $_SESSION['sum'] = null;
    header('Location: '.esc_url( home_url('/')). 'cart');
?>

先頭で「/* Template Name: empty */」とコメントアウトし、固定ページにテンプレートとして認識されるようにします。

foreach文でカートに入れた全商品の在庫数を入れる前の在庫数に戻します。

delete_post_meta()で全商品の注文数とIDのカスタムフィールドの値をforeach文で削除します。

全セッション変数にnullを代入してリセット後、header()でカートページに戻ります。

固定ページでempty.phpをテンプレートに選択したページを作成すればカートを空にするボタンが機能します。

カートページを完成させる

最後に、固定ページでカートページを作成します。タイトルは「カート」でテンプレートは先ほど作成したcartを選択し、パーマリンクをcartにします。

これでカートページは完成です。

cookieが削除されたときにカートに入れた商品を元に戻す

一定期間閲覧しなかったときや閲覧履歴を削除したときにcookieが削除されてセッションが切れ、カートに入れた商品は全て削除されて在庫数は減ったままとなってしまいます。
なので、セッションが切れた後にカートに入れた商品を戻すため、在庫数に入れた数量を加えて元に戻す処理を行います。

functions.phpに以下のコードを書きます。

functions.php

if(@$_SERVER['HTTP_COOKIE'] === null) {
    global $wpdb;
    $order_id = 'order_id';
    $stock = 'stock';
    $order_num = 'order_num';

    $all_order_id = $wpdb->get_col($wpdb->prepare(
        "SELECT DISTINCT meta_value FROM $wpdb->postmeta WHERE meta_key = %s;",
        $order_id
    ));

    $current_order_id = '';
    $current_stock = '';
    $current_order_num = '';

    foreach($all_order_id as $key => $value) {
        $current_order_id = $wpdb->get_var($wpdb->prepare(
            "SELECT DISTINCT meta_value FROM $wpdb->postmeta WHERE meta_key = %s AND post_id = %d;",
            $order_id, $value
        ));


        $current_stock = $wpdb->get_var($wpdb->prepare(
            "SELECT DISTINCT meta_value FROM $wpdb->postmeta WHERE meta_key = %s AND post_id = %d;",
            $stock, $value
        ));

        $current_order_num = $wpdb->get_var($wpdb->prepare(
            "SELECT DISTINCT meta_value FROM $wpdb->postmeta WHERE meta_key = %s AND post_id = %d;",
            $order_num, $value
        ));

        if(!empty(get_post_meta($current_order_id, 'order_num', true))) {
            update_post_meta($current_order_id, 'stock', $current_stock + $current_order_num);
            delete_post_meta($current_order_id, 'order_id');
            delete_post_meta($current_order_id, 'order_num');
            $wpdb->query( 
                $wpdb->prepare( 
                    "DELETE FROM $wpdb->postmeta
                    WHERE meta_key = %s
                    ",
                    $current_order_id 
                )
            );

            $wpdb->query( 
                $wpdb->prepare( 
                    "DELETE FROM $wpdb->postmeta
                    WHERE meta_key = %s
                    ",
                    $current_order_num 
                )
            );
        }
    }
}

if(@$_SERVER['HTTP_COOKIE'] === null) {}$_SERVER['HTTP_COOKIE']nullである、つまりcookieが削除されている場合の処理です。

WordPressのPHPコードからデータベースとやり取りするには$wpdbオブジェクトにアクセスする必要があります。
で、$wpdbオブジェクトにアクセスするには$wpdbをグローバル変数として宣言します。

クエリを発行します。始めにデータベースのwp_postmetaテーブルからmeta_key(カスタムフィールドのキー名)がorder_idmeta_value(カスタムフィールドの値)、つまりカートに入れた商品のIDを全て配列で取得し、これを$all_order_idとします。また、取得する際にDISTINCT meta_valueで、重複したmeta_valueが存在すれば先に見つかった方のみを選択します。

次にforeach文で$all_order_idからorder_idを一つずつ取り出し、post_idorder_idであるという条件にします。続けてmeta_keyがカスタムフィールドのキー($order_id, $order_stock, $order_num)であるという条件を加え、これらの条件に一致するmeta_valueSELECTしてカートに入れた商品毎のID、在庫数、数量をそれぞれ$current_order_id$current_stock$current_order_numとして取得します。

update_post_meta()で注文数order_numが0ではない商品の現在の在庫数$current_stockに注文数を足した値をカスタムフィールドstockの値に上書きして在庫数を元に戻します。

その後、delete_post_meta()でカスタムフィールドorder_idorder_numの値、つまりIDと注文数を削除します。
念のためカスタムフィールドの値だけでなくデータベースに保存されているIDと注文数も削除します。

メインメニューにカートへのリンクを表示する

メインメニューにカートへのリンクを表示するために項目を追加します。これでいつでもカートの中身を確認することができます。メニューの作成については【WordPress】カスタムメニュー機能を利用してメニューを作成して表示する方法をご覧ください。

以上で終わります。