CMB2-Snippet-Library icon indicating copy to clipboard operation
CMB2-Snippet-Library copied to clipboard

Update widget snippet with working group fields

Open rubengc opened this issue 7 years ago • 10 comments

I am trying to make group fields work at widgets area

First I added a new loop to add group fields correctly:

        public function cmb2( $saving = false ) {

            // Create a new box in the class
            $cmb2 = new CMB2( array(
                'id'      => $this->option_name .'_box', // Option name is taken from the WP_Widget class.
                'hookup'  => false,
                'show_on' => array(
                    'key'   => 'options-page', // Tells CMB2 to handle this as an option
                    'value' => array( $this->option_name )
                ),
            ), $this->option_name );

            foreach ( $this->fields as $field ) {
                if ( ! $saving ) {
                    $field['id'] = $this->get_field_name( $field['id'] );
                }

                $field['default_cb'] = array( $this, 'default_cb' );

                $field_id = $cmb2->add_field( $field );

                // Support for group fields
                if( $field['type'] == 'group' ) {
                    foreach( $field['fields'] as $group_field ) {
                        $cmb2->add_group_field( $field_id, $group_field );
                    }
                }
            }

            return $cmb2;
        }

And the js event to make repeatables working:

(function( window, document, $, cmb ) {
    $( document ).on('widget-updated widget-added', function( event, widget ) {
        var $metabox = $(widget).find('.cmb2-wrap > .cmb2-metabox');
        
        $metabox
            .on('click', '.cmb-add-group-row', cmb.addGroupRow)
            .on('click', '.cmb-add-row-button', cmb.addAjaxRow)
            .on('click', '.cmb-remove-group-row', cmb.removeGroupRow)
            .on('click', '.cmb-remove-row-button', cmb.removeAjaxRow);
    });
})( window, document, jQuery, window.CMB2 );

But I miss something, because i got a duplicated group fields in each group, and also save functionallity is not working

Can someone help me to get it working?

Thanks in advance!

rubengc avatar May 12 '17 07:05 rubengc

After investigate it, I do not need add any extra check for group fields at widget class

The value is stored correctly, but for some reason is not loaded correctly

rubengc avatar May 12 '17 07:05 rubengc

is possible that default_cb is not called on repeatable groups because it returns false instead of null?

rubengc avatar May 12 '17 09:05 rubengc

I try to override how CMB2 is getting group values because is trying to retrieve a wrong options index

I dumped the contents of $args in cmb2_override_meta_value and It has type => post instead of options-page (and metabox has correctly configured show_on argument)

I need to investigate It a bit more

rubengc avatar May 12 '17 12:05 rubengc

I got some progress about this

I am able to get group field elements values, but for some reason it only return the first element

        public function cmb2( $saving = false ) {

            // Create a new box in the class
            $cmb2 = new CMB2( array(
                'id'      => $this->option_name .'_box', // Option name is taken from the WP_Widget class.
                'hookup'  => false,
                'show_on' => array(
                    'key'   => 'options-page', // Tells CMB2 to handle this as an option
                    'value' => array( $this->option_name )
                ),
            ), $this->option_name );

            foreach ( $this->fields as $field ) {
                if ( ! $saving ) {
                    $field['id'] = $this->get_field_name( $field['id'] );
                }

                if( $field['type'] == 'group' ) {
                    // Update group fields default_cb
                    foreach( $field['fields'] as $group_field_index => $group_field ) {
                        $group_field['default_cb'] = array( $this, 'default_cb' );

                        $field['fields'][$group_field_index] = $group_field;
                    }
                }

                $field['default_cb'] = array( $this, 'default_cb' );

                $cmb2->add_field( $field );
            }

            return $cmb2;
        }
        public function default_cb( $field_args, $field ) {
            if( $field->group ) {
                if( isset( $this->_instance[ $field->group->args( 'id_key' ) ] ) ) {
                    $data = $this->_instance[ $field->group->args( 'id_key' ) ];

                    return is_array( $data ) && isset( $data[ $field->group->index ][ $field->args( 'id_key' ) ] )
                        ? $data[ $field->group->index ][ $field->args( 'id_key' ) ]
                        : null;
                } else {
                    return null;
                }
            }

            return isset( $this->_instance[ $field->args( 'id_key' ) ] )
                ? $this->_instance[ $field->args( 'id_key' ) ]
                : null;
        }

rubengc avatar May 15 '17 06:05 rubengc

Finally I got it working, I need to add a filter to cmb2_override_meta_value to retrieve correctly group field value

rubengc avatar May 15 '17 14:05 rubengc

@rubengc would you be willing to submit a PR on the widget snippet so we can see what worked and potentially add that code to the snippet library?

jazzsequence avatar May 15 '17 16:05 jazzsequence

The problem (that i hackily solved) is CMB2 do not call default_cb on group field but default_cb is called in fields inside a group

If CMB2 adds this check to group fields probably my solution will not be needle

rubengc avatar May 16 '17 05:05 rubengc

👍 This is really an issue in CMB2, then, rather than the snippet library, but I will leave it open here for context.

jazzsequence avatar May 16 '17 14:05 jazzsequence

public function form( $instance ) {
        add_filter( 'cmb2_override_meta_value', array( $this, 'cmb2_override_meta_value' ), 11, 4 );

        // If there are no settings, set up defaults
        $this->_instance = wp_parse_args( (array) $instance, self::$defaults );

        $cmb2 = $this->cmb2();

        $cmb2->object_id( $this->option_name );
        CMB2_hookup::enqueue_cmb_css();
        CMB2_hookup::enqueue_cmb_js();
        $cmb2->show_form();

        remove_filter( 'cmb2_override_meta_value', array( $this, 'cmb2_override_meta_value' ) );
    }

public function cmb2_override_meta_value( $value, $object_id, $args, $field ) {
        if ( $field->group || 'group' === $field->type() ) {
            if ( isset( $field->args['id_key'] ) ) {
                $id_key = $field->args['id_key'];

                if ( isset( $this->_instance[$id_key] ) ) {
                    $value = $this->_instance[$id_key];
                }
            }
        }

        return $value;
    }
 public function cmb2( $saving = false ) {

            // Create a new box in the class
            $cmb2 = new CMB2( array(
                'id'      => $this->option_name .'_box', // Option name is taken from the WP_Widget class.
                'hookup'  => false,
                'show_on' => array(
                    'key'   => 'options-page', // Tells CMB2 to handle this as an option
                    'value' => array( $this->option_name )
                ),
            ), $this->option_name );

            foreach ( $this->fields as $field ) {
                if ( ! $saving ) {
                    $field['id'] = $this->get_field_name( $field['id'] );
                }

                if( $field['type'] == 'group' ) {
                    // Update group fields default_cb
                    foreach( $field['fields'] as $group_field_index => $group_field ) {
                        $group_field['default_cb'] = array( $this, 'default_cb' );

                        $field['fields'][$group_field_index] = $group_field;
                    }
                }

                $field['default_cb'] = array( $this, 'default_cb' );

                $cmb2->add_field( $field );
            }

            return $cmb2;
        }

 public function default_cb( $field_args, $field ) {
            if( $field->group ) {
                if( isset( $this->_instance[ $field->group->args( 'id_key' ) ] ) ) {
                    $data = $this->_instance[ $field->group->args( 'id_key' ) ];

                    return is_array( $data ) && isset( $data[ $field->group->index ][ $field->args( 'id_key' ) ] )
                        ? $data[ $field->group->index ][ $field->args( 'id_key' ) ]
                        : null;
                } else {
                    return null;
                }
            }

            return isset( $this->_instance[ $field->args( 'id_key' ) ] )
                ? $this->_instance[ $field->args( 'id_key' ) ]
                : null;
        }

(function( window, document, $ ) {
    $( document ).on('widget-updated widget-added', function( event, widget ) {
        var $metabox = $(widget).find('.cmb2-wrap > .cmb2-metabox'),
            cmb = window.CMB2;

        $metabox
            .on('click', '.cmb-add-group-row', cmb.addGroupRow)
            .on('click', '.cmb-add-row-button', cmb.addAjaxRow)
            .on('click', '.cmb-remove-group-row', cmb.removeGroupRow)
            .on('click', '.cmb-remove-row-button', cmb.removeAjaxRow)
            .on( 'click', '.cmbhandle, .cmbhandle + .cmbhandle-title', cmb.toggleHandle );

    });
})( window, document, jQuery );

av-nexter avatar Nov 20 '17 17:11 av-nexter

Note: ColorPicker fields gets destroyed after field save on widgets area a way to fix it:

// Auto Call plugin is class is color-picker
jQuery( document ).ready( function( $ ) {
	$( '.color-picker' ).wpColorPicker();

	 // Initialize on widgets area
	$(document).on('widget-updated widget-added', function(e, widget) {
		widget.find( '.color-picker, .cmb2-colorpicker' ).wpColorPicker();
	});
} );

An explanation on this can be found here

rubengc avatar Aug 01 '19 10:08 rubengc