最新消息:Welcome to the puzzle paradise for programmers! Here, a well-designed puzzle awaits you. From code logic puzzles to algorithmic challenges, each level is closely centered on the programmer's expertise and skills. Whether you're a novice programmer or an experienced tech guru, you'll find your own challenges on this site. In the process of solving puzzles, you can not only exercise your thinking skills, but also deepen your understanding and application of programming knowledge. Come to start this puzzle journey full of wisdom and challenges, with many programmers to compete with each other and show your programming wisdom! Translated with DeepL.com (free version)

customization - How to save widget fields generated from an array?

matteradmin9PV0评论

I created simple php abstract widget class that can generate form with fields from an array. When I try to save fields, all changes are removed.

Abstract Widget Class:

<?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 );

    }

}

Widget code:

<?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'];
    }

}

Thank you so much in advance!

I created simple php abstract widget class that can generate form with fields from an array. When I try to save fields, all changes are removed.

Abstract Widget Class:

<?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 );

    }

}

Widget code:

<?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'];
    }

}

Thank you so much in advance!

Share Improve this question edited Jan 4, 2019 at 22:24 Michael asked Jan 2, 2019 at 17:23 MichaelMichael 1821 silver badge11 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 1 +50

OK, so I've done some debugging and I know where your problem lies...

First of all in update function:

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;
}

You shouldn't use $old_instance as starting point. What if the list of fields is changed? Old values shouldn't get copied to new instance. So you should use this instead:

public function update( $new_instance, $old_instance ) {

    $instance = array();

    if ( empty( $this->fields ) ) {
        return $instance;
    }

    $instance = $this->save_fields( $new_instance, $old_instance );

    return $instance;
}

But then there is one more problem in save_fields function... Again, you start with $old_instance as starting point:

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;

So if given field is a group, then:

  1. You get its fields values using recursive call.
  2. In that call you:
    1. Initiate values with old_instance.
    2. Get fields from that group and set their values.
  3. Merge group values with instance values.

So there are few problems here:

  • in 3. the values for group fields contains not only values for that group, because they were initiated with old_instance,
  • in 3. you overwrite new values from group_instance with old values from instance (which contains old values, because it is also initiated with old_instance).

So how to fix that?

It's a really simple fix, this time. All you need to do is to change:

$instance = $old_instance;

to:

$instance = array();

in both update and save_fields functions.

It works like a charm after that change.

Post a comment

comment list (0)

  1. No comments so far