我创建了一个简单的php抽象小部件类,它可以用数组中的字段生成表单。当我尝试保存字段时,所有更改都将被删除。
抽象小部件类:
<?php
/**
 * Abstract widget class
 *
 * @class MOD_Widget
 */
// Exit if accessed directly.
if ( ! defined( \'ABSPATH\' ) ) {
    exit;
}
/**
 * MOD_Widget
 *
 * @version  1.0.0
 * @extends  WP_Widget
 */
abstract class MOD_Widget extends WP_Widget {
    /**
     * CSS class.
     *
     * @var string
     */
    public $widget_cssclass;
    /**
     * Widget description.
     *
     * @var string
     */
    public $widget_description;
    /**
     * Widget ID.
     *
     * @var string
     */
    public $widget_id;
    /**
     * Widget name.
     *
     * @var string
     */
    public $widget_name;
    /**
     * Fields.
     *
     * @var array
     */
    public $fields;
    /**
     * Constructor.
     */
    public function __construct() {
        $widget_ops = array(
            \'classname\'   => $this->widget_cssclass,
            \'description\' => $this->widget_description,
            \'customize_selective_refresh\' => true,
        );
        parent::__construct( $this->widget_id, $this->widget_name, $widget_ops );
    }
    public function save_fields( $new_instance, $old_instance, $parent_container = null ) {
        // Vars
        $instance = $old_instance;
        $widget_fields = $this->fields;
        if( isset( $parent_container ) ){
            $widget_fields = $widget_fields[ $parent_container ][\'sub_fields\'];
        }
        // Loop fields and get values to save.
        foreach ( $widget_fields as $key => $setting ) {
            $setting_type = isset( $setting[\'type\'] ) ? $setting[\'type\'] : \'\';
            // Format the value based on fields type.
            switch ( $setting_type ) {
                case \'group\':
                        $group_instance = $this->save_fields( $new_instance, $old_instance, $key );
                        $instance = array_merge( $group_instance, $instance );
                    break;
                case \'number\':
                    $instance[ $key ] = (int) $new_instance[ $key ];
                    if ( isset( $setting[\'min\'] ) && \'\' !== $setting[\'min\'] ) {
                        $instance[ $key ] = max( $instance[ $key ], $setting[\'min\'] );
                    }
                    if ( isset( $setting[\'max\'] ) && \'\' !== $setting[\'max\'] ) {
                        $instance[ $key ] = min( $instance[ $key ], $setting[\'max\'] );
                    }
                    break;
                case \'text\':
                    $instance[ $key ] = isset( $new_instance[ $key ] ) ? sanitize_text_field( $new_instance[ $key ] ) : ( isset( $setting[\'default_value\'] ) ? $setting[\'default_value\'] : \'\' );
                    break;
                case \'textarea\':
                    $instance[ $key ] = wp_kses_post( $new_instance[ $key ] );
                    break;
                case \'checkbox\':
                    $instance[ $key ] = empty( $new_instance[ $key ] ) ? 0 : 1;
                    break;
                default:
                    $instance[ $key ] = isset( $new_instance[ $key ] ) ? sanitize_text_field( $new_instance[ $key ] ) : ( isset( $setting[\'default_value\'] ) ? $setting[\'default_value\'] : \'\' );
                    break;
            }
        }
        return $instance;
    }
    /**
     * Handles updating settings for the current widget instance.
     */
    public function update( $new_instance, $old_instance ) {
        $instance = $old_instance;
        if ( empty( $this->fields ) ) {
            return $instance;
        }
        $instance = $this->save_fields( $new_instance, $old_instance );
        return $instance;
    }
    /**
    * Back-end widget fields
    */
    public function field_generator( $instance, $parent_container = null ) {
        // Vars
        $widget_fields = $this->fields;
        if( isset( $parent_container ) ){
            $widget_fields = $widget_fields[ $parent_container ][\'sub_fields\'];
        }
        foreach ( $widget_fields as $key => $setting ) {
            $setting_type = isset( $setting[\'type\'] ) ? $setting[\'type\'] : \'\';
            $input_css_classes = isset( $setting[\'class\'] ) ? $setting[\'class\'] : \'\';
            if( !isset( $setting_type ) ){
                return;
            }
            if( \'group\' !== $setting_type ){
                $default_value = isset( $setting[\'default_value\'] ) ? $setting[\'default_value\'] : \'\';
                $value = isset( $instance[ $key ] ) ? $instance[ $key ] : $default_value;
            } else {
                $value = \'\';
            }
            switch ( $setting_type ) {
                case \'group\':
                    ?>
                    <div id="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>" class="mod-widget-section<?php if ( ! empty( $input_css_classes ) ) echo \' \' . implode( \' \', $input_css_classes ); ?>">
                        <div class="section-header"><?php echo esc_html( $setting[\'label\'] ); ?></div>
                        <div class="section-content">
                            <?php
                            if ( !isset( $setting[\'sub_fields\'] ) || empty( $setting[\'sub_fields\'] ) ) {
                                echo \'<p>\' . esc_html( \'This section is empty.\', \'mod\' ) . \'</p></div></div></div>\';
                                return;
                            } ?>
                            <?php $this->field_generator( $instance, $key ); ?>
                        </div>
                    </div>
                    <?php
                    break;
                case \'text\':
                    ?>
                    <div class="mod-widget-option mod-option-type-<?php echo esc_attr( $setting[\'type\'] ); ?>">
                        <label for="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>" class="mod-field-label"><?php echo esc_html( $setting[\'label\'] ); ?></label>
                        <input id="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>" type="text" class="widefat<?php if ( ! empty( $input_css_classes ) ) echo \' \' . implode( \' \', $input_css_classes ); ?>" name="<?php echo esc_attr( $this->get_field_name( $key ) ); ?>" value="<?php echo esc_attr( $value ); ?>" />
                        <?php if ( ! empty( $setting[\'desc\'] ) ) : ?>
                            <p class="small-desc"><?php echo esc_html( $setting[\'desc\'] ); ?></p>
                        <?php endif; ?>
                    </div>
                    <?php
                    break;
                case \'textarea\':
                    ?>
                    <div class="mod-widget-option mod-option-type-<?php echo esc_attr( $setting[\'type\'] ); ?>">
                        <label for="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>" class="mod-field-label"><?php echo esc_html( $setting[\'label\'] ); ?></label>
                        <textarea id="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>" class="widefat<?php if ( ! empty( $input_css_classes ) ) echo \' \' . implode( \' \', $input_css_classes ); ?>" name="<?php echo esc_attr( $this->get_field_name( $key ) ); ?>" rows="4" cols="20"><?php echo esc_textarea( $value ); ?></textarea>
                        <?php if ( ! empty( $setting[\'desc\'] ) ) : ?>
                            <p class="small-desc"><?php echo esc_html( $setting[\'desc\'] ); ?></p>
                        <?php endif; ?>
                    </div>
                    <?php
                    break;
                case \'number\':
                    ?>
                    <div class="mod-widget-option mod-option-type-<?php echo esc_attr( $setting[\'type\'] ); ?>">
                        <label for="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>" class="mod-field-label"><?php echo esc_html( $setting[\'label\'] ); ?></label>
                        <input id="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>" type="number" class="tiny-text<?php if ( ! empty( $input_css_classes ) ) echo \' \' . implode( \' \', $input_css_classes ); ?>" name="<?php echo esc_attr( $this->get_field_name( $key ) ); ?>" step="<?php echo esc_attr( $setting[\'step\'] ); ?>" min="<?php echo esc_attr( $setting[\'min\'] ); ?>" <?php if ( ! empty( $setting[\'max\'] ) ) : ?>max="<?php echo esc_attr( $setting[\'max\'] ); ?>"<?php endif; ?> value="<?php echo esc_attr( $value ); ?>" />
                        <?php if ( ! empty( $setting[\'desc\'] ) ) : ?>
                            <p class="small-desc"><?php echo esc_html( $setting[\'desc\'] ); ?></p>
                        <?php endif; ?>
                    </div>
                    <?php
                    break;
                case \'checkbox\':
                    ?>
                    <div class="mod-widget-option mod-option-type-<?php echo esc_attr( $setting[\'type\'] ); ?>">
                        <input id="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>" type="checkbox" class="checkbox<?php if ( ! empty( $input_css_classes ) ) echo \' \' . implode( \' \', $input_css_classes ); ?>" name="<?php echo esc_attr( $this->get_field_name( $key ) ); ?>" <?php echo checked( $value, 1 ); ?> />
                        <label for="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>" class="mod-checkbox-label"><?php echo esc_html( $setting[\'label\'] ); ?></label>
                        <?php if ( ! empty( $setting[\'desc\'] ) ) : ?>
                            <p class="small-desc"><?php echo esc_html( $setting[\'desc\'] ); ?></p>
                        <?php endif; ?>
                    </div>
                    <?php
                    break;
                // Default: run an action.
                default:
                    do_action( \'mod_widget_field_\' . $setting_type, $key, $value, $setting, $instance );
                    break;
            }
        }
    }
    /**
     * Outputs the settings form for the widget.
     */
    public function form( $instance ) {
        if ( empty( $this->fields ) ) {
            return;
        }
        $this->field_generator( $instance );
    }
}
 小部件代码:
<?php
/**
 * Widget - 
 *
 * @version 1.0.0
 */
defined( \'ABSPATH\' ) || exit;
/**
 * Widget - Test.
 */
class MOD_Widget_Test extends MOD_Widget {
    /**
     * Constructor.
     */
    public function __construct() {
        $this->widget_cssclass = \'mod mod_widget_test_abstract\';
        $this->widget_description = __( \'A widget description.\', \'mod\' );
        $this->widget_id = \'mod-widget-test\';
        $this->widget_name = __( \'MOD Widget - Test\', \'mod\' );
        $this->fields = array(
            \'base_title\' => array(
                \'label\' => __( \'Base Title\', \'mod\' ),
                \'type\' => \'text\',
                \'class\' => \'\',
                \'default_value\' => \'Test\',
            ),
            \'about_title\' => array(
                \'label\' => __( \'About Title\', \'mod\' ),
                \'type\' => \'text\',
                \'class\' => \'\',
                \'default_value\' => \'\',
            ),
            \'base_num\' => array(
                \'label\' => __( \'Base Number\', \'mod\' ),
                \'type\' => \'number\',
                \'class\' => \'\',
                \'default_value\' => 10,
                \'min\' => -1,
                \'step\' => 1,
            ),
            \'base_checkbox\' => array(
                \'label\' => __( \'Base Checkbox\', \'mod\' ),
                \'type\' => \'checkbox\',
                \'class\' => \'\',
                \'default_value\' => 0,
            ),
            // General
            \'group_general\' => array(
                \'label\' => __( \'General\', \'mod\' ),
                \'type\' => \'group\',
                \'sub_fields\' => array(
                    \'general_title\' => array(
                        \'label\' => __( \'General Title\', \'mod\' ),
                        \'type\' => \'text\',
                        \'class\' => \'\',
                        \'default_value\' => \'\',
                    ),
                    \'general_num\' => array(
                        \'label\' => __( \'General Number\', \'mod\' ),
                        \'type\' => \'number\',
                        \'class\' => \'\',
                        \'default_value\' => \'\',
                        \'min\' => -1,
                        \'step\' => 1,
                    ),
                    \'general_checkbox\' => array(
                        \'label\' => __( \'General Checkbox\', \'mod\' ),
                        \'type\' => \'checkbox\',
                        \'class\' => \'\',
                        \'default_value\' => 1,
                    ),
                ),
            ),
            // Special
            \'group_special\' => array(
                \'label\' => __( \'Special Parameters\', \'mod\' ),
                \'type\' => \'group\',
                \'sub_fields\' => array(
                    \'special_title\' => array(
                        \'label\' => __( \'Special Title\', \'mod\' ),
                        \'type\' => \'text\',
                        \'class\' => \'\',
                        \'default_value\' => \'\',
                    ),
                    \'special_desc\' => array(
                        \'label\' => __( \'Special Description\', \'mod\' ),
                        \'type\' => \'textarea\',
                        \'class\' => \'\',
                        \'default_value\' => \'\',
                    ),
                ),
            ),
        );
        parent::__construct();
    }
    /**
     * Output widget.
     *
     * @see WP_Widget
     *
     * @param array $args     Arguments.
     * @param array $instance Widget instance.
     */
    public function widget( $args, $instance ) {
        ob_start();
        echo $args[\'before_widget\'];
        echo \'<pre>\';
        var_dump( $instance );
        echo \'</pre>\';
        echo $args[\'after_widget\'];
    }
}
 提前非常感谢!