Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Repeating Groups with Repeating Text Fields #348

Open
bearded-avenger opened this issue Jun 5, 2015 · 20 comments
Open

Repeating Groups with Repeating Text Fields #348

bearded-avenger opened this issue Jun 5, 2015 · 20 comments
Labels

Comments

@bearded-avenger
Copy link

We lean on CMB2 to create quizzes. These quizzes have questions (repeatable groups). Within each question, the admin can create answers (repeatable text field). Here's an example of one of the repeatable groups structure.

image 2015-06-05 at 7 58 48 am

When the data is saved, it removes all but one of the questions. To replicate:

  • First group field - add 3 repeating text fields
  • click "add group" - add 3 repeating text fields
  • do this two more times to make a total of 5 repeating field groups, with each group having 3 repeating text fields
  • publish the post

When you refresh the page:

  • repeating group fields 2,3,4 now only have 2 repeating text fields (it removed the last)
  • it added a 6th group with two random answers

Here's the sample code:

        // instantiate metabox
        $cmb = new_cmb2_box( array(
            'id'            => '_quiz_metabox',
            'title'         => 'Quiz Questions',
            'object_types'  => array( 'cgc_quiz' )
        ) );

        $cmb->add_field( array(
            'name'       => 'Public Quiz',
            'id'         => '_is_public',
            'type'       => 'checkbox'
        ) );

        $cmb->add_field( array(
            'name'       => 'XP Worth',
            'id'         => '_question_xp',
            'type'       => 'text_small'
        ) );

        $cmb->add_field( array(
            'name'       => 'Questions to Display',
            'desc'       => 'Image URL',
            'id'         => '_total_questions',
            'type'       => 'select',
            'default'       => '4',
            'options'       => array(
                '4'     => '4',
                '6'     => '6',
                '8'     => '8'
            ),
        ) );

        // $group_field_id is the field id string, so in this case: $prefix . 'demo'
        $group_id = $cmb->add_field( array(
            'id'                => '_quiz_questions',
            'type'              => 'group',
            'description'       => 'A Question with Answers',
            'options'           => array(
                'group_title'   => 'Question {#}',
                'add_button'    => 'Add Another Question',
                'remove_button' => 'Remove Question',
                'sortable'      => true
            )
        ) );

        $cmb->add_group_field( $group_id, array(
            'id'            => 'question',
            'name'          => __('Question', 'cgc-quiz'),
            'type'          => 'textarea',
            'desc'          => 'Type the question here.'
        ) );

        $cmb->add_group_field( $group_id, array(
            'id'            => 'image',
            'name'          => __('Image', 'cgc-quiz'),
            'type'          => 'file',
            'desc'          => 'Optional image.'
        ) );

        $cmb->add_group_field( $group_id, array(
            'id'            => 'answers',
            'name'          => __('Answers', 'cgc-quiz'),
            'type'          => 'text',
            'sortable'      => true,
            'repeatable'     => true,
            'repeatable_max' => 10
        ) );

        $cmb->add_group_field( $group_id, array(
            'id'            => 'correct',
            'name'          => __('Correct Answer', 'cgc-quiz'),
            'type'          => 'text'
        ) );
@davekellam
Copy link

I was running into the same problem with repeating fields inside a repeater. Also had seemingly random data loss, couldn't discern any sort of pattern.

@mikemcalister
Copy link

Hey folks, I'm also seeing random data loss when using repeatable fields inside a repeat group. We've also noticed that the sorting function may also be responsible for data loss in the same instance.

Here's a gist of my code for reference. https://gist.github.com/mikemcalister/be840ff5cb9243c63bfd

@sc0ttkclark
Copy link
Contributor

Could this be reaching the internal $_POST limit in PHP for how many input_vars it will process?

@sc0ttkclark
Copy link
Contributor

Relevant PHP config vars are max_input_vars / max_input_nesting_level

@jaxgeller
Copy link

This might be slightly off-topic, but I think I'm running into a post limit as well, but with creating more than 99 repeating groups. Any time I create a 100th group and save, the 100th group does not get saved. There seems to be hard limit on 99 repeating groups.

@mikemcalister
Copy link

I was able to solve my issue of data loss by increasing the max_input_vars as @sc0ttkclark had suggested. Thanks, Scott!

You can increase that limit a few different ways. If you have access to your php.ini file, you can change it there. Otherwise you can add it via your .htaccess file by adding this:

php_value max_input_vars 5000

@jaxgeller
Copy link

@mikemcalister it worked (.htaccess). Thank you!

@mikemcalister
Copy link

No problem! I stress tested it with many, many inputs with no issues. Feel free to push that number up if you need to.

@jtsternberg
Copy link
Member

wow, nice suggestion @sc0ttkclark. Also wow guys.. 100 groups! shudders

@bearded-avenger
Copy link
Author

beautiful!!!

@sc0ttkclark
Copy link
Contributor

@jtsternberg once you give people an admin UI to do all this, things get crazy, I've seen actual sites using Pods with hundreds of content types (post types, taxonomies, advanced content types, etc), with 50-150 fields each, it's just dang crazy what people do with what we make. We ran into this very issue ourselves. Our solution was actually to take each 'row' of fields and json encode them before the form save kicks off.

The problem stemmed from the Pods Admin area, where we let you edit a Pod and all of it's fields from one screen. Each field expanded to allow you to edit a few main fields, but there were tabs with other field options available too. All total, maybe 20-40 inputs per field would be on the page to POST. Add 20-30 fields, and that really starts adding up. We found this when testing Pods 2.0 and had to resolve it through our json hack-around. In our AJAX action handler for saving the Pod, we had to loop through all of the fields passed in, then json_decode the data: https://github.com/pods-framework/pods/blob/master/classes/PodsAdmin.php#L2315

Yep, it was fun times. We broke PHP, we broke much of the world. But I share that knowledge with you, for I see that we'll be having much more fun with CMB2 group fields in Pods too :)

@jtsternberg
Copy link
Member

Ha ha @sc0ttkclark, those are stories you'll be able to pass on to the next generation.

That being said, your experience in that area will be invaluable.

@MuhammadRehman
Copy link

Woow!! Really amazing and helpful!..

@ogdsgn
Copy link

ogdsgn commented Mar 31, 2017

Hello All,

I've run into this bug and haven't been able to resolve it using the PHP config vars.

I have a Repeatable group which contains a repeatable text field. If I create one group everything works fine, however, when I make a second group with another 5 text fields - the data gets messed up on save.

screen shot 2017-03-30 at 10 37 31 pm

Here is the result after making a second group of the same # of text fields and saving.

To replicate:

  1. First group field - add 5 repeating text fields
  2. Click "add group" - add 5 repeating text fields
  3. publish the post

When you refresh the page:

  • The second group only has 2 fields,
  • A 3rd, 4th, and 5th group is created with one text field each.
  • And there is a 6th empty group

screen shot 2017-03-30 at 10 49 27 pm

Here's the sample code:

$group_rates_id = $cmb_shelter_rates->add_field( array(
	'id'          => $prefix . 'rates',
	'type'        => 'group',
	'options'     => array(
		'group_title'   => esc_html__( 'Rate {#}', 'cmb2' ), 
		'add_button'    => esc_html__( 'Add Another Rate', 'cmb2' ),
		'remove_button' => esc_html__( 'Remove Rate', 'cmb2' ),
	),
) );	

$cmb_shelter_rates->add_group_field( $group_rates_id, array(
	'name'       => esc_html__( 'Custom Rate Details', 'cmb2' ),
	'id'         => 'rate_details',
	'repeatable' => true,
	'type'       => 'text',
) );

Thanks in advance!

@tw2113
Copy link
Contributor

tw2113 commented Mar 31, 2017

Something is definitely getting mangled up during the save/serialize process, but I'm not sure what, and I have to wonder if its in part because of the javascript involved to repeater fields.

As an alternative, in case you're willing to consider it, perhaps try out setting a cap at amount of custom rate details can be added, and provide a field for each. Say 5 total. Just a thought.

@ogdsgn
Copy link

ogdsgn commented Apr 5, 2017

Yeah, that was my fallback, just wanted to see if the repeater would be useable first.

cheers!

@nisan92
Copy link

nisan92 commented Jun 22, 2017

I am running into same problem as @ogdsgn asked, and this problem is still unsolved.

@unnamedfeeling
Copy link

This issue persists - when user creates multiple group elements width multiple repeating fields inside they get sorted inside these group elements. This one is a really annoying bug serialization/save bug(((

@daggerhart
Copy link
Contributor

daggerhart commented Nov 6, 2017

I did a bit of debugging on this issue today and believe I've identified the issue, but unfortunately didn't get a working patch.

The problem seems to be coming from the cmb.elReplacements function in cmb2.js. This function is handling the replacement of field names and IDs when both a new row, and new group is created.

The regex in this function is replacing the first instance of the previous index with the next index. The problem here is that when you have a repeatable field inside of a repeatable group, there are multiple indices that need to be taken into account.

For example, assume you have these fields:

$group_field_id = $cmb->add_field( array(
	'id'          => 'my_group',
	'type'        => 'group',
) );

$cmb->add_group_field( $group_field_id, array(
	'name' => 'Repeating field',
	'id'   => 'my_field',
	'type' => 'text',
	'repeatable' => true,
) );

The name for the first field in the first group will be: my_group[0][my_field][0].

Following these steps, and you'll get the following field name results:

  • Add new field: my_group[0][my_field][1]
  • Add new field: my_group[0][my_field][2]
  • Add new Group: my_group[1][my_field][0] - So far so good, but here is where it starts breaking.
  • Add new field in the new Group: my_group[1][my_field][3] - Suddenly field 3
  • Add new field in the new Group: my_group[2][my_field][3] - Suddenly group 2
  • Add new field in the new Group: my_group[3][my_field][3] - etc...

What appears to be happening is that the data-iterator is being correctly reset to 1 for a new group, but when that happens the regex used to handle the newName and newId starts replacing the group's index instead of the field's, because the group's index of [1] is the first match found during oldName.replace( '['+ prevNum +']', '['+ cmb.idNumber +']' ).

If you continue adding new Groups, each with three or four fields in it, you'll notice that the field names get further and further off from being correct. It's because this regex keeps replacing the first match it finds, regardless of that match being the group's index or the field's index.

I believe the best way to fix this is to separate this into two functions, one for creating a new group and another for creating a new field. This way, we can tell the "new group" regex to only replace the first match found starting at the beginning of the string, and we can tell the "new field" regex to replace the first match found starting at the end of the string.

In my attempts today, I was trying to do something quick and dirty to determine if a field or group was being created, and adjust the regex accordingly, but I didn't have much luck with that approach.

Regardless. To clarify, I am 99% sure this is a javascript bug and not a php serialization bug because the problem is very apparent when inspecting the fields as they are created.

@daggerhart
Copy link
Contributor

Found a related issue with a patch: #1035

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests