Jump to content

Adding and Assigning Fields without using gui?


neildaemond

Recommended Posts

Hi,

Is there an easy way to add fields and then assign it to templates besides going through the admin gui? I find it slows down development anytime I think of a new field and have to manually add it then assign it to all the templates I need it in... (would be a nice feature if we could add the field to multiple templates at the time of creating the new field)

Looking at the cheatsheet, I see I can see how to set the name, title, and label of a field using $field->name ... etc.

checking the advanced tab in the cheatsheet I can see the the the $fields-save() etc...

but I'm not really sure how to create a field object or what its structure is like~

does anyone create these via scripts? how do you guys do it?

  • Like 1
Link to comment
Share on other sites

Hey neil (are you neil?),

I'd say go check out the source of configurable modules. The code for building the configuration options is there - you'd only save the fields into db:

	// this is a container for fields, basically like a fieldset
	$fields = new InputfieldWrapper();

	// since this is a static function, we can't use $this->modules, so get them from the global wire() function
	$modules = wire('modules');

	// Populate $data with the default config, because if they've never configured this module before,
	// the $data provided to this function will be empty. Or, if you add new config items in a new version,
	// $data won't have it until they configure it. Best bet is to merge defaults with custom, where
	// custom overwrites the defaults (array_merge).
	$data = array_merge(self::getDefaultData(), $data);

	// showModal field
	$field = $modules->get("InputfieldCheckbox");
	$field->name = "showModal";
	$field->label = "Use modal window";
	$field->description = "Whether open pages in modal (overlay) window or goes to traditional administration.";
	$field->value = 1; // providing a "checked" value for the checkbox is necessary
	$field->attr('checked', empty($data['showModal']) ? '' : 'checked');
	$fields->add($field);

	return $fields;

This is from latest AdminBar by @apeisa. You can see the '$field' part, where the field is built. You probably only run $field->save() at the end instead of current $fields->add() and you have just created field via code :) Adding fields to the template will be probably close to the ->add() call, and I'm totally not sure about reordering them in the templates via code, you might need to play with this a little.

  • Like 4
Link to comment
Share on other sites

You can assign fields to templates like this:

$template = $templates->get("some_template");
$template->fields->add("newfield");
$template->fields->save();

this code is taken from here http://processwire.c...bles/templates/

So, just make an array with all the templates you want the field to be on, and go for it :)

$ts = array("home", "basic-page", "search");
foreach($ts as $t){
 $template = $templates->get($t);
 $template->fields->add("newfield");
 $template->fields->save();
}

EDIT: the field will be on the last position of each template

  • Like 6
Link to comment
Share on other sites

This is the way to create template and fields with API:

// new fieldgroup
$fg = new Fieldgroup();
$fg->name = 'new-template';
$fg->add($this->fields->get('title')); // needed title field
$fg->save();

// new template using the fieldgroup
$t = new Template();
$t->name = 'new-template';
$t->fieldgroup = $fg; // add the fieldgroup
$t->noChildren = 1;
$t->save();

// add one more field, attributes depending on fieldtype
$f = new Field(); // create new field object
$f->type = $this->modules->get("FieldtypeFloat"); // get a field type
$f->name = 'price';
$f->precision = 2;
$f->label = 'Price of the product';
$f->save(); // save the field
$fg->add($f); // add field to fieldgroup
$fg->save(); // save fieldgroup

All pretty much standard OO one can figure out looking at core and PW modules. But not someone unexperienced would figure out by themself. I think at some point we need to cover these in a documentation.

  • Like 16
Link to comment
Share on other sites

Another option (though one I don't use often) is the 'global' checkbox available in the 'advanced' tab of the field editor. (Though I think this one may only be available if $config->advanced is set to true in your /site/config.php). Anyway, once you check that box and save the field, it then requires all your templates to have that field. And it will add it to any templates that don't.

Link to comment
Share on other sites

awesome! That's pretty straight forward... I guess I should have looked at the core, but I thought someone might already be doing this sort of thing~

You can assign fields to templates like this:
 $template = $templates->get("some_template"); $template->fields->add("newfield"); $template->fields->save(); 

this code is taken from here http://processwire.c...bles/templates/ So, just make an array with all the templates you want the field to be on, and go for it :)

$ts = array("home", "basic-page", "search"); foreach($ts as $t){ $template = $templates->get($t); $template->fields->add("newfield"); $template->fields->save(); }

EDIT: the field will be on the last position of each template

Thanks! I think I'll start off by making fields in the gui, then just adding the field to templates should be a breeze using this script... I'll try creating fields and templates after i get a little more comfortable... maybe even try doing it through the php command line interface. That'll be the boss round though.

Hey neil (are you neil?)

yes, I am :)

Link to comment
Share on other sites

  • 10 months later...
  • 4 months later...

I am trying to create a basic setup script that I can use to pre-populate my new ProcessWire installs with the fields and templates I use on the majority of sites I create. To do this I'm bootstrapping PW in a php file I've created in my site's root:

<?php
// Bootstrap ProcessWire
include('./index.php');

// Assign API variables to make things a little easier
$fields = wire("fields");
$templates = wire("templates");
$modules = wire("modules");

// Edit existing fields

$f = $fields->body;
$f->rows = 30;
$f->save();

$f = $fields->sidebar;
$f->rows = 30;
$f->save();


// Redirect template

if(!$fields->redirect_page) {
	$f = new Field();
	$f->type = $modules->get("FieldtypePage");
	$f->name = 'redirect_page';
	$f->label = 'Link to a Page';
	$f->inputfield = 'InputfieldPageListSelect';
	$f->save();
}

if(!$fields->redirect_url) {
	$f = new Field();
	$f->type = $modules->get("FieldtypeURL");
	$f->name = 'redirect_url';
	$f->label = 'Link to an off-site URL';
	$f->noRelative = 1;
	$f->addRoot = 0;
	$f->placeholder = 'http://www.website.com/';
	$f->save();
}

if(!$templates->redirect) {
	$t = new Template();
	$t->name = 'redirect';
	$t->fields->add("redirect_page");
	$t->fields->add("redirect_url");
	$t->save();
}

echo 'Default setup is complete!';

Everything seems to work except for the last bit on the bottom where I try and assign the fields to the new "redirect" template. I get the error message "Error: Call to a member function add() on a non-object"

I know it's probably something simple, but I can't figure it out! Any ideas?

Edit: As usual, I figure out my problem as soon as I post my question on the forums :)

Here is the working code:

<?php
// Bootstrap ProcessWire
include('./index.php');

// Assign API variables to make things a little easier
$fields = wire("fields");
$templates = wire("templates");
$modules = wire("modules");

// Edit existing fields

$f = $fields->body;
$f->rows = 30;
$f->save();

$f = $fields->sidebar;
$f->rows = 30;
$f->save();


// Create redirect template & fields

$newTemplateName = 'redirect';

if(!$fields->redirect_page) {
	$f = new Field();
	$f->type = $modules->get("FieldtypePage");
	$f->name = 'redirect_page';
	$f->label = 'Link to a Page';
	$f->inputfield = 'InputfieldPageListSelect';
	$f->save();
}

if(!$fields->redirect_url) {
	$f = new Field();
	$f->type = $modules->get("FieldtypeURL");
	$f->name = 'redirect_url';
	$f->label = 'Link to an off-site URL';
	$f->noRelative = 1;
	$f->addRoot = 0;
	$f->placeholder = 'http://www.website.com/';
	$f->save();
}

if(!$templates->$newTemplateName) {
	$fg = new Fieldgroup();
	$fg->name = $newTemplateName;
	$fg->add("title");
	$fg->add("redirect_page");
	$fg->add("redirect_url");
	$fg->save();
	
	$t = new Template();
	$t->name = $newTemplateName;
	$t->fieldgroup = $fg;
	$t->save();
}

echo 'Default setup is complete!';

I am still unclear on what a Fieldgroup is and why I need to create one in order to make any changes to the template's field assignments. It feels like a bit of a clumsy extra step to have to go through because it doesn't seem to have any representation on the PW admin interface. I'm sure there's a good reason for it, though, knowing Ryan.

  • Like 1
Link to comment
Share on other sites

I think you need fieldgroup to add fields first and then add fieldgroup to template. Look at apeisa's shop module for examples.

Oops or couple posts above nice guy soma has some example. :-)

  • Like 2
Link to comment
Share on other sites

Thanks Soma, I figured it out, but now I'm just a little confused as to why.

But I see that now that once the fieldgroup has already been created for the template and assigned to it, I can add another field simply by doing:

$t = $templates->get('templateName');
$t->fields->add("fieldName");
$t->fields->save();
 

Which is much quicker.

Is there any way to reorder the fields in a template through the API?

  • Like 1
Link to comment
Share on other sites

Is there any way to reorder the fields in a template through the API?

See the cheatsheet documentation at http://cheatsheet.processwire.com/ and click the "advanced" button, then click "WireArray/PageArray". All the methods for WireArray are at your disposal for this. Specifically the section on "Setting/Modifying Items" is probably the most helpful. A WireArray only carries one of each item, so if you add/insert/etc. an item that's already present, it'll move it in the array rather than add another copy. 

  • Like 3
Link to comment
Share on other sites

I am still unclear on what a Fieldgroup is and why I need to create one in order to make any changes to the template's field assignments. It feels like a bit of a clumsy extra step to have to go through because it doesn't seem to have any representation on the PW admin interface. I'm sure there's a good reason for it, though, knowing Ryan.

It's hidden in the admin interface unless you've got advanced mode on. I've tried to keep the admin as simple as possible so that people can think of templates and fieldgroups as one in the same thing. But the reality is that they are actually separate things. The benefit of having them separate is that you can have multiple templates sharing the same group of fields. But currently we're not highlighting that behavior on the admin side just because I think there is more benefit to the clarity of templates just being a single thing. i had always thought we'd expand on the behavior on the admin side in giving people more options, but the need seems rare enough that it's stayed in advanced mode for now. Probably what I will end up doing is making the API itself abstract the behavior too, so that it adds a like-named Fieldgroup automatically when you access $template->fields and one isn't already there. 

  • Like 3
Link to comment
Share on other sites

  • 4 weeks later...
  • 1 month later...

I've used API code to create a whole bunch of TextLanguage input fields, with the example @ http://processwire.com/talk/topic/1051-adding-and-assigning-fields-without-using-gui/?p=36795

Worked like a charm. Now my question: Is it possible to also assign distinct labels for each language via API? (I have a multilang site, using 2.3.2 and MultiLangPageNames)

Should I use somehow wire('user')->language and switch for each lang. in my script?

Or can I add a parameter directly to $f->label = "foo"?

Link to comment
Share on other sites

Nobody has any idea? I wasn't sure if I should rather post this question in one of the multilang forum threads, open a new one, or post here. (and I sure hate to cross-post)

I'll be probably soon receiving a massive MS-Excel list of data that has to be exported to PW via API. The data won't be in the default language, so I'd really be eager to know how this can be accomplished via API (if at all - but knowing PW, I guess it's definitely just 2-3 lines of code...).

Link to comment
Share on other sites

You can assign language-specific labels or descriptions to fields by setting either $field->label or $field->description with the language ID appended to it. Since the string value of a $language is its ID, this you can just do it like this: 

$es = $languages->get('es'); 
$fr = $languages->get('fr'); 

$field->set("label$es", "Spanish Label"); 
$field->set("description$es", "Spanish Description"); 
$field->set("label$fr", "French Label");
$field->set("description$fr", "French Description"); 

The above is resolving to something like this (where 123 is the ID of Spanish and 456 is the ID of French):

$field->label123 = "Spanish Label";
$field->description123 = "Spanish Description";
$field->label456 = "French Label";
$field->description456 = "French Description";

When setting for the 'default' language, make sure you are setting just "label" and "description" without anything appended. For instance, this won't work:

$en = $languages->get("default"); 
$field->set("label$en", "English Label"); // this is incorrect because default language has no ID appended
$field->set("label", "English Label"); // this is correct
$field->label = "English Label"; // this is also correct
  • Like 4
Link to comment
Share on other sites

Thanks!

But sadly, this doesn't work (no error messages either). I put this in the site root - I'm probably missing something?

// Bootstrap ProcessWire
include('./index.php');

// Assign API variables
$fields = wire("fields");
$templates = wire("templates");
$languages = wire("languages");

$en = $languages->get('en');
$us = $languages->get('us');
$fr = $languages->get('fr');

$field = $fields->get('prod_max_power_consumption');

$field->set("label$en", "Max. Power Consumption TEST");
$field->set("label$us", "Max. Power Consumption TEST");
$field->set("label$fr", "Max. consommation de courant TEST");
Link to comment
Share on other sites

  • 1 year later...

yup.  building out the cms for the client really does eat up a lot of time when you're loading pages, saving, saving again, navigating to another admin page, etc.  tasks become redundant but i suppose that's the drawback of a GUI. 

this script based setup is very interesting.  i do wish the process was a bit simpler for us primarily-front-end developers though. OOP? scary. i've seen some cms using yaml to setup fields.  that looks more friendly. see here for statamic's method to get an idea. 

who wants to build a module that would allow us to import a yaml file to translate into new fields?

question: where do you run these scripts?  so i code up one of these php files to create a bunch of fields.  where do i put this file (in the structure of pw) and run it? 

Link to comment
Share on other sites

Since 2013 a bunch of things changed. I'd suggest taking a look at the core import/export feature for files/templates. Sadly the formatting there is quite strict, but if done carefully you can make for example batch changes in a texteditor and import the changes back into pw. 

Link to comment
Share on other sites

  • 2 years later...
3 hours ago, nickngqs said:

So how do you guys execute this? Which folder do I put and so on.

You have three possibilities.  The first one, you can write the code in a template file inside your site/template folder, the second you can write the code in a bootstrapped script in the root directory (or where you want, you just have to adjust the path of the index.php). The thrid, inside a module.

Read the whole thread, you should find what you need. What are you trying to achieve ?

Edited by flydev
module
  • Like 3
Link to comment
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.
×
×
  • Create New...