Jump to content
thetuningspoon

Assigning Fields to Repeaters with the API

Recommended Posts

Hi!

I have been struggling with this for the last few hours and could not find a solution for it anywhere on the forums. I want to create a repeater field using the API and then add fields to it programatically. I can create the field and assign it to a template alright, but I can't assign any fields to the repeater itself.

I've tried using $field->repeaterFields when creating the field but cannot figure out what it's supposed to accept. I tried passing it an array of IDs as well as a fieldgroup, but I couldn't get either to work.

Any ideas?

Share this post


Link to post
Share on other sites

Sorry, I don't have much time, and maybe someone else will provide a simpler answer, but I went through the process of figuring this out for a module. It was more complicated because I was creating the repeater fields from JSON, but if you search through this code:

https://github.com/adrianbj/ProcessPageTreeMigrator/blob/master/ProcessPageTreeMigrator.module for "repeater" you should find what you need in there.

Sorry I can't be of more help right now.

Share this post


Link to post
Share on other sites

Thanks adrian, but I'm having trouble following along with what's happening in your code.

I discovered that the system is automatically creating a system template/fieldgroup for the repeater with the repeater_xxx naming convention, but it's not created until after I've gone into the admin and gone in to edit the repeater field. So I tried grabbing the fieldgroup after creating the field in the code and adding to it right away, but it seems that the fieldgroup doesn't actually exist yet?

So yeah, I think I'm going to need a simpler answer :)

Share this post


Link to post
Share on other sites

Adrian, I just found your post here: http://processwire.com/talk/topic/4736-add-inputfieldrepeater-to-module-configuration-page/

I tried replicating your process for setting up the fieldgroup, field, and template, but PW keeps creating a filedgroup & template with a different name (adding a 1 to the end of it) instead of using the one I created.

EDIT:

Here is my code:

$repeaterName = "sc_promos";
$f = new Field();
			$f->type = $this->modules->get("FieldtypeRepeater");
			$f->name = $repeaterName;
		
			$repeaterFg = new Fieldgroup();
			$repeaterFg->name = "repeater_$repeaterName";
			
			//Add fields to fieldgroup - add others as necessary
			$repeaterFg->append($this->fields->get("sc_promo_active"));
			
			$repeaterFg->save();
			
			$repeaterT = new Template();
			$repeaterT->name = "repeater_$repeaterName";
			$repeaterT->flags = 8;
			$repeaterT->noChildren = 1;
			$repeaterT->noParents = 1;
			$repeaterT->noGlobal = 1;
			$repeaterT->slashUrls = 1;
			$repeaterT->fieldgroup = $repeaterFg;
			
			$repeaterT->save();
			
			//Now, add the fields directly to the repeater
			$f->repeaterFields = $this->fields->get("sc_promo_active");
			
			$f->save();
			
			//Add the sc_promos repeater field to the sc-promo-codes fieldgroup
			$fg->add($f);
			$fg->save();

Share this post


Link to post
Share on other sites

Good find - I had forgotten about that post :)

I just used the code from that other post of mine on a fresh PW install (latest dev, although I think it should work on 2.3 stable as well) and it works perfectly.

I know that when I was playing around with writing that code I often messed up the PW database to the point where I was getting errors and found the best way was to do a fresh install again.

BUT, I just noticed that you are missing these key lines in your version:

$repeater_page = "for-field-{$f->id}";
$f->parent_id = $this->pages->get("name=$repeater_page")->id;
$f->template_id = $repeater_template->id;
$f->repeaterReadyItems = 3;

This is critical to make things work.

Let me know how you go.

  • Like 3

Share this post


Link to post
Share on other sites

YESYESYESYESYES!!!!  That was it! I thought that that particular bit of code wasn't necessary because I only wanted to create the repeater and not any associated pages. I'm not sure why it works but it does :)

Yes, I've had to go in and manually hack the database due to errors along the way, but all is working well, so I don't think I've messed up anything too bad :)

I do have to say... this is way complicated for ProcessWire since most things in PW tend to be surprisingly easy. But I don't think Ryan foresaw repeaters being created this way. I'm sure this is something that could be simplified in the future.

  • Like 1

Share this post


Link to post
Share on other sites

I agree it does seem complicated, but so long as it works for you :)

On mobile at the moment, but I might try to clean up that codea little and comment it better so people know what's going on.

Glad it worked for you!

Share this post


Link to post
Share on other sites

Maybe we could put together a function that would take the repeater name and desired fields as inputs and do all the hard work of creating the fieldgroup, template, and page... If I get a few extra minutes I may give that a try.

Share this post


Link to post
Share on other sites

Exactly what I was thinking. If you don't get to it, I'll do it when I am back at my computer.

Share this post


Link to post
Share on other sites

Well, I'm no pro at this and you could probably improve it, but here's my attempt which serves my current needs pretty well:

	/**
	 * Creates a repeater field with associated fieldgroup, template, and page
	 *
	 * @param string $repeaterName The name of your repeater field
	 * @param string $repeaterFields List of field names to add to the repeater, separated by spaces
	 * @param string $repeaterLabel The label for your repeater
	 * @param string $repeaterTags Tags for the repeater field
	 * @return Returns the new Repeater field
	 *
	 */
	public function createRepeater($repeaterName,$repeaterFields,$repeaterLabel,$repeaterTags)
	{
		$fieldsArray = explode(' ',$repeaterFields);
		
		$f = new Field();
		$f->type = $this->modules->get("FieldtypeRepeater");
		$f->name = $repeaterName;
		$f->label = $repeaterLabel;
		$f->tags = $repeaterTags;
		$f->repeaterReadyItems = 3;
		
		//Create fieldgroup
		$repeaterFg = new Fieldgroup();
		$repeaterFg->name = "repeater_$repeaterName";
		
		//Add fields to fieldgroup
		foreach($fieldsArray as $field) {
			$repeaterFg->append($this->fields->get($field));
		}
		
		$repeaterFg->save();
		
		//Create template
		$repeaterT = new Template();
		$repeaterT->name = "repeater_$repeaterName";
		$repeaterT->flags = 8;
		$repeaterT->noChildren = 1;
		$repeaterT->noParents = 1;
		$repeaterT->noGlobal = 1;
		$repeaterT->slashUrls = 1;
		$repeaterT->fieldgroup = $repeaterFg;
		
		$repeaterT->save();
		
		//Setup page for the repeater - Very important
		$repeaterPage = "for-field-{$f->id}";
		$f->parent_id = $this->pages->get("name=$repeaterPage")->id;
		$f->template_id = $repeaterT->id;
		$f->repeaterReadyItems = 3;
		
		//Now, add the fields directly to the repeater field
		foreach($fieldsArray as $field) {
			$f->repeaterFields = $this->fields->get($field);
		}
		
		$f->save();
		
		return $f;
	}

And here's an example of calling it:

$f = $this->createRepeater("sc_promos","sc_promo_active sc_promo_code sc_promo_discount","Promotional Offer","shoppingCart");

You can then use $f to add your new repeater field to a fieldgroup/template.

  • Like 12

Share this post


Link to post
Share on other sites

Nice work - that's pretty much exactly what I was thinking.

I am not sure about setting the flags to system and permanent though as the defaults for a function. I think there should at least be a comment on that line that users should adjust to their needs as I don't think this is a typical use case.

Glad to see that code of mine is getting some use - I have to say it was quite an effort to figure out and as you said, very un-PW in its complexity. I would love to hear from Ryan as to whether there is an easier way to achieve this.

Also, for the sake of putting all the information about creating and working with repeaters from the API in one thread, I think it is worth mentioning the special getNew() method for creating repeater items. It is used in the Page Tree Migrator module and described in detail on this page: http://processwire.com/api/fieldtypes/repeaters/

  • Like 3

Share this post


Link to post
Share on other sites

Nice work - that's pretty much exactly what I was thinking.

Thanks!

I am not sure about setting the flags to system and permanent though as the defaults for a function. I think there should at least be a comment on that line that users should adjust to their needs as I don't think this is a typical use case.

Good point. I removed that line from the code altogether.

Share this post


Link to post
Share on other sites

Thanks everfreecreative for that convenient function, I was fiddling around with that myself atm.

Is is save to delete the template, fieldgroup and field to delete the whole thing or will there be any unused relational pairings left in the database?

Share this post


Link to post
Share on other sites

Is is save to delete the template, fieldgroup and field to delete the whole thing or will there be any unused relational pairings left in the database?

I think that will do it.

Share this post


Link to post
Share on other sites
Is is save to delete the template, fieldgroup and field to delete the whole thing or will there be any unused relational pairings left in the database?

I know this is old and I am not sure if this is still the case, but when I last looked into this I actually had to do the following to fully clean up a repeater field:

$current_field_id = $this->fields->get("field_name")->id;

$forfieldid = "for-field-$current_field_id";
$sql = "DELETE FROM pages WHERE name=:forfieldid";
$query = $this->wire('database')->prepare($sql);
$query->bindValue(':forfieldid', $forfieldid);
$query->execute();

Here's a related Github issue (https://github.com/ryancramerdesign/ProcessWire/issues/368) and forum post (https://processwire.com/talk/topic/4440-deletepage-true-doesnt-delete-repeated-fields-on-230/). Note that Post #10 by yours truly describes the issue which the above fix deals with. I think this is different to the other things described.

I know this has become a little off-topic now, but wanted to respond to owzim's question with some details and potential issues.

  • Like 1

Share this post


Link to post
Share on other sites

I know this is a pretty old thread, but every time it comes to creating a Repeater through the API, I get LOST.

@thetuningspoon's function illuminates a LOT of what happens behind the scenes when a new Repeater is made through the GUI - but I just keep wishing it was as simple as:

$f = new FieldtypeRepeater();
$f->set('name', 'repeaterTest');
$f->add($repeaterField1);
$f->add($repeaterField2);
$f->save();

Because that isn't technically possible without setting the Fieldgroup or Template that will be used by the Repeater first, right?

 

At the end of the day, I think we should improve the docs for Repeaters (https://processwire.com/api/fieldtypes/repeaters/) to include a section on creating a Repeater from scratch through the API so that this process is more easily understood. I am always referencing several Forum posts and parts of the docs in order to get through the spaghetti - having everything in one place would be great.

Otherwise it would be awesome to have some functions as a part of the FieldtypeRepeater Class that cut down on the amount of API calls one needs to make in order to create one of these.

 

Just my 2 cents.

  • Like 6

Share this post


Link to post
Share on other sites

Has anyone have any experience adding fields to Repeater Matrix items (through the API of course)? Like, add a new field to certain repeater matrix type.

Share this post


Link to post
Share on other sites
7 hours ago, elabx said:

Has anyone have any experience adding fields to Repeater Matrix items (through the API of course)? Like, add a new field to certain repeater matrix type.

Probably a question best answered by Ryan in the pro support board, but this worked for me...

// Name of repeater matrix field
$matrix_field_name = 'test_matrix';

// Name of matrix type you want to add field to
$matrix_type_name = 'type_1';

// Name of field you want to add to matrix type
$add_field_name = 'images';

// Get field objects
$matrix_field = $fields->get($matrix_field_name);
$add_field = $fields->get($add_field_name);

// Add field to repeater matrix fieldgroup
$matrix_template = $templates->get("repeater_$matrix_field_name");
$matrix_fieldgroup = $matrix_template->fieldgroup;
$matrix_fieldgroup->add($add_field);
$matrix_fieldgroup->save();

// Associate field with matrix type
$matrix_types = $matrix_field->type->getMatrixTypes($matrix_field);
$matrix_type_integer = $matrix_types[$matrix_type_name];
$property = "matrix{$matrix_type_integer}_fields";
$field_ids_in_type = $matrix_field->$property;
$field_ids_in_type[] = $add_field->id;
$matrix_field->$property = $field_ids_in_type;
$matrix_field->save();

 

  • Like 4

Share this post


Link to post
Share on other sites

Is this thread still alive? Has something changed so far, so that repeater fields could be added in a more elegant way (I mean, when added programmatically)? 🙂

Share this post


Link to post
Share on other sites

  For me, it looks like, adding to property repeaterFields does not work correctly. Changed it to the following:

$repeaterFieldIds = [];

foreach($fieldsArray as $field) {
  $repeaterFieldIds[] = $this->fields->get($field)->id;
}

$f->repeaterFields = $repeaterFieldIds;
    
$f->save();

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By marcus
      wireshell 1.0.0 is out    
      See Bea's post
       


      -------- Original post -----------
        Now this one could be a rather long post about only an experimental niche tool, but maybe a helpful one for some, so stay with me   Intention Do you guys know "Artisan" (Laravel) or "Drush" (Drupal)? If not: These are command line companions for said systems, and very useful for running certain (e.g. maintenance, installation) task quickly - without having to use the Admin Interface, first and foremost when dealing with local ProcessWire installations. And since it has a powerful API and an easy way of being bootstrapped into CLIs like this, I think such a tool has a certain potential in the PW universe.    It's totally not the first approach of this kind. But: this one should be easily extendable - and is based on PHP (specifically: the Console component of the Symfony Framework). Every command is tidily wrapped in its own class, dependencies are clearly visible, and so on.   ( Here was the outdated documentation. Please visit wireshell.pw for the current one )
    • By michelangelo
      Hello guys,
      very simple question about repeaters from the Core Modules. I have used them before without issues. This one concerns a weird behaviour which I am not sure whether it's caused by me not using it correctly or a bug. The problem is that when I add content, save it, refresh the page and return to the page, I cannot unfold the repeater. I made a video so you can see the behaviour (below)
      I tried re-initiating the repeater field, but still doesn't work...

      Looking forward to your advice!

      Thanks!


       
      repeater-problem.mp4
    • By benbyf
      Hello, and welcome to what I though was either my client being silly and changing things, or some evil doer. Turns out its reproducible and therefore something in Proceswire (I checked my templates and modules but couldnt find anything that would be doing this...). So what is it doing? Check out the video for evidence.
      A repeater field is interacting with a page template and another repeater field somehow to swap the fields in the template and repeater over...
      I have a template called team, and a repeater field called team_repeater with label Team. Some how and for some reason, when I change my fields on repeater called main_menu_links my team template gets those fields and when I try and revert the team template fields to the fields it should have, they get given to the repeater main_menu_links. Also this to say HELP!!!!!
      video: https://www.dropbox.com/s/exkdhc6n7x0xpsa/strange-repeater-PW-mega-bug.mov?dl=0
    • By neonwired
      I have a front end form for creating new pages, repeater and repeater matrix field don't seem to save any data. I was considering handling the data manually but can't seem to get anything useful from the post data, are there any methods i can use?
    • By quickjeff
      Hi Guys, 
      I have been debugging a site for the last 2 hours and cannot solve the issue. 
      I have a site running on 3.0.148. 
      I installed the Kongondo Blog module and was updating the templates to include the website style. 
      Once everything was set and done, I checked the page tree to see an error appear. 
      Template must be assigned a name before 'filename' can be accessed
      The same error appears in templates. 
      Debugging Steps
      I checked the templates in the server to ensure I didnt accidentally delete the namespace.  Deleted cache in browser and server under assets Still no go. 
      Any help is appreciated. 
      Thanks! 
×
×
  • Create New...