参考外观:
功能代码:使用时插入到主题functions.php文件中即可。或者保存在其他文件中,使用require方法调用。
<?php
function faq() {
    new set_faq();
}
if (is_admin()) {
    add_action('load-post.php', 'faq');
    add_action('load-post-new.php', 'faq');
}
class set_faq {
    public function __construct() {
        add_action('add_meta_boxes', array($this, 'add_faq'));
        add_action('save_post', array($this, 'save_faq'));
    }
    public function add_faq($post_type) {
        $post_types = array('products');
        if (in_array($post_type, $post_types)) {
            add_meta_box('repeatable-fields', 'Q&A', array($this, 'kohken2019_repeatable_meta_box_display'), $post_type, 'normal', 'high');
        }
    }
    public function kohken2019_repeatable_meta_box_display($post) {
        $kohken_repeatable_faq_fields = get_post_meta($post->ID, 'kohken_repeatable_faq_fields', true);
        wp_nonce_field('kohken2019_repeatable_meta_box_nonce', 'kohken2019_repeatable_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.insertBefore('#repeatable-fieldset-one .faq_body>dl:last');
            return false;
        });

        $('.remove-row').on('click', function() {
            $(this).parents('dl').remove();
            return false;
        });
    });
</script>
<style>
    .add_btn{
        display: flex;
        justify-content: flex-start;
    }
    .add_btn .button-primary{
        display: flex;
        align-items:center;
        justify-content: center;
    }
    .add_btn .button-primary svg,.faq_body .remove .remove-row svg{
        width: 1em;
        min-width: 1em;
        height: 1em;
        margin-left: 6px;
    }
    .add_btn .button-primary svg path,.faq_body .remove .remove-row svg path{
        fill:#ffffff;
    }
    .faq_body .remove{
        display: flex;
        justify-content: flex-end;
    }
    .faq_body .remove .remove-row{
        display: flex;
        align-items:center;
        justify-content: center;
        background-color: #cc3c36;
        color: white;
        border:0;
    }
    .faq_body dl:not(:last-child){
        margin-bottom: 10px;
        padding: 15px;
        background-color: #fff;
    }
    .faq_body dl dt,.faq_body dd{
        margin: 0;
        display: flex;
        align-items: flex-start;
        justify-content: flex-start;
    }
    .faq_body dl dt input{
        font-weight: bold;
        font-size:1.1em;
    }
    .faq_body dl dt strong,.faq_body dd strong{
        font-weight: bold;
        font-size:18px;
        margin-right: 3px;
        white-space: nowrap;
        text-transform: uppercase;
        line-height: 1.8em;
        min-width: 1.1em;
        opacity: 0.9;
    }
    .faq_body dd{
        margin: 6px 0;
    }
    .faq_body dd textarea{
        width:100% !important;
        max-width: none;
    }
    .faq_body dd.remove{
        margin-bottom: 0;
    }
</style>
<div id="repeatable-fieldset-one" width="100%">
    <div class="faq_body">
        <?php
        if ($kohken_repeatable_faq_fields):
            foreach ($kohken_repeatable_faq_fields as $field) {
?>
        <dl>
            <dt><strong>Q</strong><input type="text" class="widefat" name="questionText[]" value="<?php
                if ($field['questionText'] != '') echo esc_attr($field['questionText']); ?>" /></dt>
            <dd><strong>A</strong><textarea type="text" class="widefat" name="answerText[]" rows="5"><?php
                if ($field['answerText'] != '') echo esc_attr($field['answerText']); ?></textarea></dd>
            <dd class="remove"><a class="button-primary remove-row" href="#"><span>Remove</span><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
                        <path d="M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zM124 296c-6.6 0-12-5.4-12-12v-56c0-6.6 5.4-12 12-12h264c6.6 0 12 5.4 12 12v56c0 6.6-5.4 12-12 12H124z"></path>
                    </svg></a></dd>
        </dl>
        <?php
            } else:
?>
        <dl>
            <dt><strong>Q</strong><input type="text" class="widefat" name="questionText[]" /></dt>
            <dd><strong>A</strong><textarea type="text" class="widefat" name="answerText[]" rows="5"></textarea></dd>
            <dd class="remove"><a class="button-primary remove-row" href="#"><span>Remove</span><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
                        <path d="M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zM124 296c-6.6 0-12-5.4-12-12v-56c0-6.6 5.4-12 12-12h264c6.6 0 12 5.4 12 12v56c0 6.6-5.4 12-12 12H124z"></path>
                    </svg></a></dd>
        </dl>
        <?php
            endif; ?>


        <dl class="empty-row screen-reader-text">
            <dt><strong>Q</strong><input type="text" class="widefat" name="questionText[]" /></dt>
            <dd><strong>A</strong><textarea type="text" class="widefat" name="answerText[]" rows="5"></textarea></dd>
            <dd class="remove"><a class="button-primary remove-row" href="#"><span>Remove</span><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
                        <path d="M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zM124 296c-6.6 0-12-5.4-12-12v-56c0-6.6 5.4-12 12-12h264c6.6 0 12 5.4 12 12v56c0 6.6-5.4 12-12 12H124z"></path>
                    </svg></a></dd>
        </dl>
    </div>
</div>

<div class="add_btn"><a id="add-row" class="button-primary" href="#"><span>Add New</span><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
            <path d="M416 208H272V64c0-17.67-14.33-32-32-32h-32c-17.67 0-32 14.33-32 32v144H32c-17.67 0-32 14.33-32 32v32c0 17.67 14.33 32 32 32h144v144c0 17.67 14.33 32 32 32h32c17.67 0 32-14.33 32-32V304h144c17.67 0 32-14.33 32-32v-32c0-17.67-14.33-32-32-32z"></path>
        </svg></a></div>
<?php
        }
        public function save_faq($post_id) {
            if (!isset($_POST['kohken2019_repeatable_meta_box_nonce']) || !wp_verify_nonce($_POST['kohken2019_repeatable_meta_box_nonce'], 'kohken2019_repeatable_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, 'kohken_repeatable_faq_fields', true);
            $new = array();
            $questionTexts = $_POST['questionText'];
            $answerTexts = $_POST['answerText'];
            $count = count($questionTexts);
            for ($num = 0;$num < $count;$num++) {
                if ($questionTexts[$num] != ''):
                    $new[$num]['questionText'] = stripslashes(strip_tags($questionTexts[$num]));
                    if ($answerTexts[$num] == '') $new[$num]['answerText'] = '';
                    else $new[$num]['answerText'] = stripslashes($answerTexts[$num]);
                endif;
            }
            if (!empty($new) && $new != $old) update_post_meta($post_id, 'kohken_repeatable_faq_fields', $new);
            elseif (empty($new) && $old) delete_post_meta($post_id, 'kohken_repeatable_faq_fields', $old);
        }
    }