WordPressカスタムフィールド:Smart Custom Fields代替とadd_meta_box

何度かこのブログでも、書いていますが、リピーターを使えるカスタムフィールドプラグインが有料しかなく、頼りだった「Custom Field Suite」の脆弱性発見による公開停止に追い打ちをかけられて、またプラグインを探す旅にでておりました。

でも、探せども見つからずたどり着いたのはfunctionへの直がき。

参考にしたのは下記のGitHubです。

バナー登録のリピーター

ひとまず作ってみたのが、バナー画像、バナータイトル、バナーURLの3つのフィールドを固定ページ1877に追加するリピーターです。

functionに追記しました。

  • 条件のフック名:ha_add_top_banners_meta_boxes
  • フック名:top_banners_meta_box_display
  • リピーターのグループ名:top_banners
  • バナー画像:top_banner_img
  • バナータイトル:top_banner_name
  • バナーURL:top_banner_url
<?php
add_action('admin_init', 'ha_add_top_banners_meta_boxes', 2);

function ha_add_top_banners_meta_boxes() {
    // 固定ページIDが1877である場合のみメタボックスを追加
    $post_id = isset($_GET['post']) ? $_GET['post'] : (isset($_POST['post_ID']) ? $_POST['post_ID'] : '');
    if ($post_id == 1877) {
        add_meta_box('top_banners_group', 'トップバナー', 'top_banners_meta_box_display', 'page', 'normal', 'default');
    }
}

function top_banners_meta_box_display() {
    global $post;
    $top_banners = get_post_meta($post->ID, 'top_banners', true);
    wp_nonce_field('top_banners_meta_box_nonce', 'top_banners_meta_box_nonce');
    ?>
    <script type="text/javascript">
    jQuery(document).ready(function($) {
        $('#add-row').on('click', function() {
            var row = $('.empty-row.screen-reader-text').clone(true);
            row.removeClass('empty-row screen-reader-text');
            row.find('input, textarea').val(''); // フィールドをクリア
            row.insertBefore('#repeatable-fieldset-one tbody>tr:last');
            return false;
        });

        $(document).on('click', '.remove-row', function() {
            $(this).parents('tr').remove();
            return false;
        });
    });
    </script>

    <table id="repeatable-fieldset-one" width="100%">
        <tbody>
            <?php
            if ($top_banners) {
                foreach ($top_banners as $field) {
                    ?>
                    <tr>
                        <td><input type="text" name="top_banner_name[]" placeholder="サイト名" value="<?php echo esc_attr($field['top_banner_name']); ?>" /></td>
                        <td>
                            <input type="hidden" name="top_banner_img[]" value="<?php echo esc_attr($field['top_banner_img']); ?>" />
                            <button class="upload_image_button button">画像を選択</button>
                            <img src="<?php echo esc_url($field['top_banner_img']); ?>" style="max-width: 150px; display: <?php echo $field['top_banner_img'] ? 'block' : 'none'; ?>" />
                        </td>
                        <td><input type="text" name="top_banner_url[]" placeholder="サイトURL" value="<?php echo esc_attr($field['top_banner_url']); ?>" /></td>
                        <td><textarea name="top_banner_txt[]" placeholder="説明文 (50文字以内)" maxlength="50"><?php echo esc_textarea($field['top_banner_txt']); ?></textarea></td>
                        <td><a class="button remove-row" href="#">削除</a></td>
                    </tr>
                    <?php
                }
            } else {
                // 空のテンプレート行
                ?>
                <tr>
                    <td><input type="text" name="top_banner_name[]" placeholder="サイト名" /></td>
                    <td>
                        <input type="hidden" name="top_banner_img[]" />
                        <button class="upload_image_button button">画像を選択</button>
                        <img src="" style="max-width: 150px; display: none;" />
                    </td>
                    <td><input type="text" name="top_banner_url[]" placeholder="サイトURL" /></td>
                    <td><textarea name="top_banner_txt[]" placeholder="説明文 (50文字以内)" maxlength="50"></textarea></td>
                    <td><a class="button remove-row" href="#">削除</a></td>
                </tr>
                <?php
            }
            ?>
            <tr class="empty-row screen-reader-text">
                <td><input type="text" name="top_banner_name[]" placeholder="サイト名" /></td>
                <td>
                    <input type="hidden" name="top_banner_img[]" />
                    <button class="upload_image_button button">画像を選択</button>
                    <img src="" style="max-width: 150px; display: none;" />
                </td>
                <td><input type="text" name="top_banner_url[]" placeholder="サイトURL" /></td>
                <td><textarea name="top_banner_txt[]" placeholder="説明文 (50文字以内)" maxlength="50"></textarea></td>
                <td><a class="button remove-row" href="#">削除</a></td>
            </tr>
        </tbody>
    </table>
    <p><a id="add-row" class="button" href="#">フィールドを追加</a></p>
    <?php
}

add_action('save_post', 'top_banners_meta_box_save');
function top_banners_meta_box_save($post_id) {
    // 固定ページIDが1877でない場合は保存しない
    if ($post_id != 1877) {
        return;
    }

    if (!isset($_POST['top_banners_meta_box_nonce']) ||
        !wp_verify_nonce($_POST['top_banners_meta_box_nonce'], 'top_banners_meta_box_nonce')) {
        return;
    }

    if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
        return;
    }

    if (!current_user_can('edit_post', $post_id)) {
        return;
    }

    $old = get_post_meta($post_id, 'top_banners', true);
    $new = array();
    $names = $_POST['top_banner_name'];
    $urls = $_POST['top_banner_url'];
    $imgs = $_POST['top_banner_img'];
    $texts = $_POST['top_banner_txt'];
    $count = count($names);

    for ($i = 0; $i < $count; $i++) {
        if ($names[$i] != '') {
            $new[$i]['top_banner_name'] = sanitize_text_field($names[$i]);
            $new[$i]['top_banner_url'] = esc_url_raw($urls[$i]);
            $new[$i]['top_banner_img'] = esc_url_raw($imgs[$i]);
            $new[$i]['top_banner_txt'] = sanitize_textarea_field($texts[$i]);
        }
    }

    if (!empty($new) && $new != $old) {
        update_post_meta($post_id, 'top_banners', $new);
    } elseif (empty($new) && $old) {
        delete_post_meta($post_id, 'top_banners', $old);
    }
}

function ha_enqueue_media_uploader() {
    wp_enqueue_media();
    ?>
    <script>
    jQuery(document).ready(function($) {
        function initImageUploader() {
            $('.upload_image_button').off('click').on('click', function(e) {
                e.preventDefault();
                var button = $(this);
                var custom_uploader = wp.media({
                    title: '画像を選択',
                    button: { text: '画像を選択' },
                    multiple: false
                }).on('select', function() {
                    var attachment = custom_uploader.state().get('selection').first().toJSON();
                    button.prev('input').val(attachment.url);
                    button.next('img').attr('src', attachment.url).show();
                }).open();
            });
        }

        initImageUploader(); // 初期化

        // 行追加時に再初期化
        $('#add-row').on('click', function() {
            setTimeout(initImageUploader, 500); // 新しい行に対応
        });
    });
    </script>
    <?php
}
add_action('admin_footer', 'ha_enqueue_media_uploader');

?>

リピーターの呼び出し

<ul class="listProject row">
          <?php $top_banners = get_post_meta(get_the_ID(), 'top_banners', true);
          if (!empty($top_banners)) {
            foreach ($top_banners as $banner) {
          ?>
              <li class="col-md-3 col-6 inview_fadeIn">
                <div class="cardItem">
                  <a href="<?php echo esc_url($banner['top_banner_url']); ?>" target="_blank">
                    <figure class="thumb"><img src="<?php echo esc_url($banner['top_banner_img']); ?>" alt="<?php echo esc_attr($banner['top_banner_name']); ?>" /></figure>
                  </a>
                  <p class="detail"><?php echo esc_html($banner['top_banner_txt']); ?></p>
                  <?php /*<a class="viewMore" href="<?php echo $fields['banner_link']; ?>" target="_blank">
                <span class="text">Webサイトへ</span>
                <div class="blank"></div>
              </a> */ ?>
                </div>
              </li>
          <?php }
          } ?>
        </ul>

add_meta_boxへの挑戦

私自身、ずっとカスタムフィールドはプラグインに頼っていたため、初の試みで不安はあるものの、WordPress 6.6.2での稼働は確認しています。通常のカスタムフィールドもadd_meta_box作成で対応可能でした。

一旦、作れれば応用できそうなので、様子を見ながら使用していこうかと思っています。
カスタムフィールドプラグインの便利さが身に沁みます。むしろ、有料化にも納得できました。

この記事をシェアする

関連記事

なぐログ
   

ナクジイ

猫4匹と同居。中学生から独学でWeb制作を始め仕事として10年ほど。Web制作依頼でお困りの方にも相談しやすく伴走したいと思い制作ノウハウだけでなく依頼者向けのコンテンツを提供。訳あって週4勤務中。おっとりしてそうに見えるらしいが、結構じっとしていられないタイプ。

Page Top