0

I created simple php class to generate fields in the widget form from an array. I don't know how to generate fields in the sections/groups and save it. Any advice and suggestions will be greatly appreciated.

My abstract class:

<?php
/**
 * Abstract widget class
 *
 * @class LWB_Widget
 */

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

/**
 * LWB_Widget
 *
 * @version  1.0.0
 * @extends  WP_Widget
 */
abstract class LWB_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;

    /**
     * Settings.
     *
     * @var array
     */
    public $settings;

    /**
     * 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 );

        add_action( 'save_post', array( $this, 'flush_widget_cache' ) );
        add_action( 'deleted_post', array( $this, 'flush_widget_cache' ) );
        add_action( 'switch_theme', array( $this, 'flush_widget_cache' ) );
    }

    /**
     * Get cached widget.
     *
     * @param  array $args Arguments.
     * @return bool true if the widget is cached otherwise false
     */
    public function get_cached_widget( $args ) {
        $cache = wp_cache_get( $this->get_widget_id_for_cache( $this->widget_id ), 'widget' );

        if ( ! is_array( $cache ) ) {
            $cache = array();
        }

        if ( isset( $cache[ $this->get_widget_id_for_cache( $args['widget_id'] ) ] ) ) {
            echo $cache[ $this->get_widget_id_for_cache( $args['widget_id'] ) ]; // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
            return true;
        }

        return false;
    }

    /**
     * Cache the widget.
     *
     * @param  array  $args Arguments.
     * @param  string $content Content.
     * @return string the content that was cached
     */
    public function cache_widget( $args, $content ) {
        $cache = wp_cache_get( $this->get_widget_id_for_cache( $this->widget_id ), 'widget' );

        if ( ! is_array( $cache ) ) {
            $cache = array();
        }

        $cache[ $this->get_widget_id_for_cache( $args['widget_id'] ) ] = $content;

        wp_cache_set( $this->get_widget_id_for_cache( $this->widget_id ), $cache, 'widget' );

        return $content;
    }

    /**
     * Flush the cache.
     */
    public function flush_widget_cache() {
        foreach ( array( 'https', 'http' ) as $scheme ) {
            wp_cache_delete( $this->get_widget_id_for_cache( $this->widget_id, $scheme ), 'widget' );
        }
    }

    /**
     * Output the html at the start of a widget.
     *
     * @param array $args Arguments.
     * @param array $instance Instance.
     */
    public function widget_start( $args, $instance ) {
        echo $args['before_widget']; // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped

        if ( $title = apply_filters( 'widget_title', empty( $instance['title'] ) ? '' : $instance['title'], $instance, $this->id_base ) ) { // phpcs:ignore Squiz.PHP.DisallowMultipleAssignments.Found, WordPress.CodeAnalysis.AssignmentInCondition.Found
            echo $args['before_title'] . $title . $args['after_title']; // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
        }
    }

    /**
     * Updates a particular instance of a widget.
     *
     * @see    WP_Widget->update
     * @param  array $new_instance New instance.
     * @param  array $old_instance Old instance.
     * @return array
     */
    public function update( $new_instance, $old_instance ) {

        $instance = $old_instance;

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

        // Loop settings and get values to save.
        foreach ( $this->settings as $key => $setting ) {

            if ( ! isset( $setting['type'] ) && 'section' !== $setting['type'] ) {
                continue;
            }

            // Format the value based on settings type.
            switch ( $setting['type'] ) {
                case 'number':
                    $instance[ $key ] = absint( $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 'textarea':
                    $instance[ $key ] = wp_kses( trim( wp_unslash( $new_instance[ $key ] ) ), wp_kses_allowed_html( 'post' ) );
                    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 ] ) : $setting['std'];
                    break;
            }

            /**
             * Sanitize the value of a setting.
             */
            $instance[ $key ] = apply_filters( 'lwb_widget_settings_sanitize_option', $instance[ $key ], $new_instance, $key, $setting );
        }

        $this->flush_widget_cache();

        return $instance;
    }

    /**
     * Outputs the settings update form.
     *
     * @see   WP_Widget->form
     *
     * @param array $instance Instance.
     */
    public function form( $instance ) {

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

        foreach ( $this->settings as $key => $setting ) {

            $class = isset( $setting['class'] ) ? $setting['class'] : '';

            switch ( $setting['type'] ) {

                case 'text':
                    ?>
                    <p>
                        <label for="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>"><?php echo $setting['label']; ?></label><?php // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped ?>
                        <input class="widefat <?php echo esc_attr( $class ); ?>" id="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( $key ) ); ?>" type="text" value="<?php echo esc_attr( $value ); ?>" />
                    </p>
                    <?php
                    break;

                case 'number':
                    ?>
                    <p>
                        <label for="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>"><?php echo $setting['label']; /* phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped */ ?></label>
                        <input class="widefat <?php echo esc_attr( $class ); ?>" id="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( $key ) ); ?>" type="number" step="<?php echo esc_attr( $setting['step'] ); ?>" min="<?php echo esc_attr( $setting['min'] ); ?>" max="<?php echo esc_attr( $setting['max'] ); ?>" value="<?php echo esc_attr( $value ); ?>" />
                    </p>
                    <?php
                    break;

                case 'select':
                    ?>
                    <p>
                        <label for="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>"><?php echo $setting['label']; /* phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped */ ?></label>
                        <select class="widefat <?php echo esc_attr( $class ); ?>" id="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( $key ) ); ?>">
                            <?php foreach ( $setting['options'] as $option_key => $option_value ) : ?>
                                <option value="<?php echo esc_attr( $option_key ); ?>" <?php selected( $option_key, $value ); ?>><?php echo esc_html( $option_value ); ?></option>
                            <?php endforeach; ?>
                        </select>
                    </p>
                    <?php
                    break;

                case 'radio':
                    ?>
                    <p>
                        <label for="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>"><?php echo $setting['label']; /* phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped */ ?></label>
                        <select class="widefat <?php echo esc_attr( $class ); ?>" id="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( $key ) ); ?>">
                            <?php foreach ( $setting['options'] as $option_key => $option_value ) : ?>
                                <option value="<?php echo esc_attr( $option_key ); ?>" <?php selected( $option_key, $value ); ?>><?php echo esc_html( $option_value ); ?></option>
                            <?php endforeach; ?>
                        </select>
                    </p>
                    <?php
                    break;

                case 'textarea':
                    ?>
                    <p>
                        <label for="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>"><?php echo $setting['label']; /* phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped */ ?></label>
                        <textarea class="widefat <?php echo esc_attr( $class ); ?>" id="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( $key ) ); ?>" cols="20" rows="3"><?php echo esc_textarea( $value ); ?></textarea>
                        <?php if ( isset( $setting['desc'] ) ) : ?>
                            <small><?php echo esc_html( $setting['desc'] ); ?></small>
                        <?php endif; ?>
                    </p>
                    <?php
                    break;

                case 'checkbox':
                    ?>
                    <p>
                        <input class="checkbox <?php echo esc_attr( $class ); ?>" id="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( $key ) ); ?>" type="checkbox" value="1" <?php checked( $value, 1 ); ?> />
                        <label for="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>"><?php echo $setting['label']; /* phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped */ ?></label>
                    </p>
                    <?php
                    break;

                case 'section':
                    ?>
                    <div class="lwb-widget-section">
                        <div class="section-header">
                            <button class="section-toggle" type="button"><?php echo $setting['label']; ?></button>
                        </div>
                        <div class="section-body">
                            <div class="section-content">
                                <?php if ( !isset( $setting['settings'] ) || empty( $setting['settings'] ) ) {
                                    echo esc_html( 'This section is empty.','lwb' );
                                    echo '</div></div></div>';
                                    return;
                                } ?>
                                <?php
                                    // Generate sub settings
                                ?>
                            </div>
                        </div>
                    </div>
                    <?php
                    break;

                // Default: run an action.
                default:
                    do_action( 'lwb_widget_field_' . $setting['type'], $key, $value, $setting, $instance );
                    break;
            }
        }
    }

    /**
     * Get widget id plus scheme/protocol to prevent serving mixed content from (persistently) cached widgets.
     *
     * @since  1.0.0
     * @param  string $widget_id Id of the cached widget.
     * @param  string $scheme    Scheme for the widget id.
     * @return string            Widget id including scheme/protocol.
     */
    protected function get_widget_id_for_cache( $widget_id, $scheme = '' ) {
        if ( $scheme ) {
            $widget_id_for_cache = $widget_id . '-' . $scheme;
        } else {
            $widget_id_for_cache = $widget_id . '-' . ( is_ssl() ? 'https' : 'http' );
        }

        return apply_filters( 'lwb_cached_widget_id', $widget_id_for_cache );
    }
}

My widget:

<?php
/**
 * Widget - Test.
 */
class LWB_Widget_Test extends LWB_Widget {

    /**
     * Constructor.
     */
    public function __construct() {
        $this->widget_cssclass    = 'lwb-widgets-boundle widget-test';
        $this->widget_description = __( "A widget to display your posts in classic layout.", 'lwb' );
        $this->widget_id          = 'lwb_posts_classic';
        $this->widget_name        = __( 'LWB - Test', 'lwb' );
        $this->settings           = array(
            'title'       => array(
                'type'  => 'text',
                'std'   => __( 'LWB - Test', 'lwb' ),
                'label' => __( 'Title', 'lwb' ),
            ),
            'text-field'  => array(
                'type'  => 'text',
                'std'   => __( 'Default value', 'lwb' ),
                'label' => __( 'Text Field', 'lwb' ),
                'desc'  => __( 'This a simple descriprion.', 'lwb' ),
            ),
            'textarea-field'  => array(
                'type'  => 'textarea',
                'std'   => __( 'Default value', 'lwb' ),
                'label' => __( 'Textarea Field', 'lwb' ),
                'desc'  => __( 'This a simple descriprion.', 'lwb' ),
            ),
            'number-field'      => array(
                'type'  => 'number',
                'step'  => 1,
                'min'   => 1,
                'max'   => '',
                'std'   => 5,
                'label' => __( 'Number Field', 'lwb' ),
                'desc'  => __( 'This a simple descriprion.', 'lwb' ),
            ),
            'select-field'        => array(
                'type'    => 'select',
                'std'     => '',
                'label'   => __( 'Select Field', 'lwb' ),
                'desc'  => __( 'This a simple descriprion.', 'lwb' ),
                'options' => array(
                    ''         => __( 'All products', 'lwb' ),
                    'featured' => __( 'Featured products', 'lwb' ),
                    'onsale'   => __( 'On-sale products', 'lwb' ),
                ),
            ),
            'checkbox-field'   => array(
                'type'  => 'checkbox',
                'std'   => 0,
                'label' => __( 'Checkbox Field', 'lwb' ),
                'desc'  => __( 'This a simple descriprion.', 'lwb' ),
            ),
            'section-field-3' => array(
                'type' => 'section',
                'label' => __('Section 3', 'lwb'),
                'hide' => true,
                'settings' => array(
                    'text-field-2'  => array(
                        'type'  => 'text',
                        'std'   => __( 'Default value', 'lwb' ),
                        'label' => __( 'Text Field', 'lwb' ),
                        'desc'  => __( 'This a simple descriprion.', 'lwb' ),
                    ),
                    'textarea-field-2'  => array(
                        'type'  => 'textarea',
                        'std'   => __( 'Default value', 'lwb' ),
                        'label' => __( 'Textarea Field', 'lwb' ),
                        'desc'  => __( 'This a simple descriprion.', 'lwb' ),
                    ),
                    'number-field-2'      => array(
                        'type'  => 'number',
                        'step'  => 1,
                        'min'   => 1,
                        'max'   => '',
                        'std'   => 5,
                        'label' => __( 'Number Field', 'lwb' ),
                        'desc'  => __( 'This a simple descriprion.', 'lwb' ),
                    ),
                    'select-field-2'        => array(
                        'type'    => 'select',
                        'std'     => '',
                        'label'   => __( 'Select Field', 'lwb' ),
                        'desc'  => __( 'This a simple descriprion.', 'lwb' ),
                        'options' => array(
                            ''         => __( 'All products', 'lwb' ),
                            'featured' => __( 'Featured products', 'lwb' ),
                            'onsale'   => __( 'On-sale products', 'lwb' ),
                        ),
                    ),
                    'checkbox-field-2'   => array(
                        'type'  => 'checkbox',
                        'std'   => 0,
                        'label' => __( 'Checkbox Field', 'lwb' ),
                        'desc'  => __( 'This a simple descriprion.', 'lwb' ),
                    ),
                ),
            ),
        );

        parent::__construct();
    }

    /**
     * Output widget.
     *
     * @see WP_Widget
     *
     * @param array $args     Arguments.
     * @param array $instance Widget instance.
     */
    public function widget( $args, $instance ) {
        if ( $this->get_cached_widget( $args ) ) {
            return;
        }

        ob_start();

        echo $args['before_widget'];

        var_dump( $instance );

        echo $args['after_widget'];

        echo $this->cache_widget( $args, ob_get_clean() ); // WPCS: XSS ok.
    }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.