Leaderboard
Popular Content
Showing content with the highest reputation on 06/05/2015 in all areas
-
So here i'm starting. This is more a little snippet than a whole module. On frontend before the </body> tag the script from http://browser-update.org/ is working - nothing fancy here. Download Github: https://github.com/mr-fan/MarkupBrowserUpdate my todo for this is: make it a clean module make use of the settings from browser-update.org so you could define these in PW backend get the backling for PW best regards mr-fan5 points
-
I've just found the following article via Twitter: https://www.cmscritic.com/a-look-at-processwires-latest-core-updates/. I haven't read it yet. I have just clicked on the link because I've seen an error worth noting... I am going to send the author a message to suggest him a change from "ProcessWire, the open source PHP platform, has some updates well worth nothing." to "ProcessWire, the open source PHP platform, has some updates well worth noting."4 points
-
<?php class DuplicateArticles extends WireData implements Module { public static function getModuleInfo() { return array( 'title' => 'Duplicate Articles When Created In English To All Translations', 'version' => 1, 'summary' => 'Module to create duplicate of English (master) articles as pages in every translated language.', 'singular' => true, 'autoload' => true, ); } public function init() { $this->pages->addHookAfter('added', $this, 'duplicate'); // This hook occurs right after saving the trash status $this->pages->addHook('trashed', $this, 'trashDuplicates'); // This hook occurs right before final deletion $this->pages->addHook('deleteReady', $this, 'deleteDuplicates'); } public function duplicate($event) { $page = $event->arguments[0]; // Only duplicate pages under /articles/ if ($page->parent_id == 1023) { $translations = new PageArray(); $a = new Page(); $a->template = 'article_french'; $a->parent = wire('pages')->get('/fr/articles/'); $a->name = $page->name; $a->title = "{$page->title} (awaiting translation)"; $a->status = Page::statusUnpublished; $a->save(); $translations->add($a); $b = new Page(); $b->template = 'article_spanish'; $b->parent = wire('pages')->get('/es/articles/'); $b->name = $page->name; $b->title = "{$page->title} (awaiting translation)"; $b->status = Page::statusUnpublished; $b->save(); $translations->add($b); … $page->translationPages->import($translations); $page->save("translationPages"); } } public function trashDuplicates($event) { $page = $event->arguments[0]; if($page->parent_id == 1023){ foreach($page->translationPages as $translation){ $pages->trash($translation); } } } public function deleteDuplicates($event) { $page = $event->arguments[0]; // It may be trashed, where the parent is not 1023 if($page->is("template=article")){ foreach($page->translationPages as $translation){ $pages->delete($translation, true); } } } } Not tested. Maybe it works out of the box, but at least it'll get you started.2 points
-
2 points
-
[quotamos]This is really interesting stuff and I'm learning so much from it. I've already tested Soma's code and it works very well. Is there a way of configuring $form->render() so that it outputs different html (divs for ul/li etc.)? [/quotamos] you.can usage. $form->setMarkup(); und $form->setClasses(); two.set markups und html caresses. see.eliamos /wire/core/InputfieldWrapper.php2 points
-
TemplateEngineTwig This module adds Twig as engine to the TemplateEngineFactory. Screenshot of the available configuration options: Project on GitHub: https://github.com/wanze/TemplateEngineTwig Project in modules directory: http://modules.processwire.com/modules/template-engine-twig/ Only Twig related things should be discussed in this thread. For common problems/features/questions about the Factory, use the TemplateEngineFactory thread.1 point
-
Just wanted to share what I recently used to create forms in modules and in frontend using the API and Inputfield modules PW provides and uses on its own. I think many newcomers or also advanced user aren't aware what is already possible in templates with some simple and flexible code. Learning this can greatly help in any aspect when you develop with PW. It's not as easy and powerful as FormBuilder but a great example of what can be archieved within PW. Really? Tell me more The output markup generated with something like echo $form->render(); will be a like the one you get with FormBuilder or admin forms in backend. It's what PW is made of. Now since 2.2.5~ somewhere, the "required" option is possible for all fields (previous not) and that makes it easier a lot for validation and also it renders inline errors already nicely (due to Ryan FormBuilder yah!). For example the Password inputfield already provides two field to confirm the password and will validate it. De- and encryption method also exists. Or you can also use columns width setting for a field, which was added not so long ago. Some fields like Asm MultiSelect would require to also include their css and js to work but haven't tried. Also file uploads isn't there, but maybe at some point there will be more options. It would be still possible to code your own uploader when the form is submitted. Validation? If you understand a little more how PW works with forms and inputfields you can simply add you own validation, do hooks and lots of magic with very easy code to read and maintain. You can also use the processInput($input->post) method of a form that PW uses itself to validate a form. So getting to see if there was any errors is simply checking for $form->getErrors();. Also the $form->processInput($input->post) will prevent CSRF attacks and the form will append a hidden field automaticly. It's also worth noting that processInput() will work also with an array (key=>value) of data it doesn't have to be the one from $input->post. Styling? It works well if you take your own CSS or just pick the inputfields.css from the templates-admin folder as a start. Also the CSS file from the wire/modules/InputfieldRadios module can be helpful to add. And that's it. It's not very hard to get it display nicely. Here an code example of a simple form. <?php $out = ''; // create a new form field (also field wrapper) $form = $modules->get("InputfieldForm"); $form->action = "./"; $form->method = "post"; $form->attr("id+name",'subscribe-form'); // create a text input $field = $modules->get("InputfieldText"); $field->label = "Name"; $field->attr('id+name','name'); $field->required = 1; $form->append($field); // append the field to the form // create email field $field = $modules->get("InputfieldEmail"); $field->label = "E-Mail"; $field->attr('id+name','email'); $field->required = 1; $form->append($field); // append the field // you get the idea $field = $modules->get("InputfieldPassword"); $field->label = "Passwort"; $field->attr("id+name","pass"); $field->required = 1; $form->append($field); // oh a submit button! $submit = $modules->get("InputfieldSubmit"); $submit->attr("value","Subscribe"); $submit->attr("id+name","submit"); $form->append($submit); // form was submitted so we process the form if($input->post->submit) { // user submitted the form, process it and check for errors $form->processInput($input->post); // here is a good point for extra/custom validation and manipulate fields $email = $form->get("email"); if($email && (strpos($email->value,'@hotmail') !== FALSE)){ // attach an error to the field // and it will get displayed along the field $email->error("Sorry we don't accept hotmail addresses for now."); } if($form->getErrors()) { // the form is processed and populated // but contains errors $out .= $form->render(); } else { // do with the form what you like, create and save it as page // or send emails. to get the values you can use // $email = $form->get("email")->value; // $name = $form->get("name")->value; // $pass = $form->get("pass")->value; // // to sanitize input // $name = $sanitizer->text($input->post->name); // $email = $sanitizer->email($form->get("email")->value); $out .= "<p>Thanks! Your submission was successful."; } } else { // render out form without processing $out .= $form->render(); } include("./head.inc"); echo $out; include("./foot.inc"); Here the code snippet as gist github: https://gist.github.com/4027908 Maybe there's something I'm not aware of yet, so if there something to still care about just let me know. Maybe some example of hooks could be appended here too. Thanks Edit March 2017: This code still works in PW2.8 and PW3.1 point
-
This is already available within the RTE, I think the same functionality should be brought through to the Image field (note: I am not asking for a media manager )1 point
-
Not a tutorial exactly - but you could perhaps look at the blog profile to see how certain things are achieved?1 point
-
building a news system could take some in depth knowledge of the api - i would read all of the docs and study the cheatsheet. the navigation is trivial; there are innumerable ways to include/exclude pages (MSN supports selectors)1 point
-
public function trashDuplicates($event) { $page = $event->arguments[0]; if($page->parent_id == 1023){ foreach($page->translated_pages as $translation){ $this->pages->trash($translation); } } } public function deleteDuplicates($event) { $page = $event->arguments[0]; // It may be trashed, where the parent is not 1023 if($page->is("template=article_english")){ foreach($page->translated_pages as $translation){ $this->pages->delete($translation, true); } } } This code shouldn't error like your error message, as pages is no longer the variable.1 point
-
Hm, maybe it works like this? $field = $modules->get("InputfieldMapMarker"); $field->label = "Localização"; $field->attr('id+name','map'); $marker = new MapMarker(); $marker->lat = "38.694147"; $marker->lng = "-9.205794"; $field->attr('value', $marker); $field->required = 0; $form->append($field);1 point
-
It's not good to reinvent the wheel, but it's not bad to know how wheels are made. What you want to do is actually quite simple, and all you need is a loop inside the first loop. For only two levels, a very simplified version could look like this: echo "<ul>"; foreach($homepage->children as $item) { // loop through the children of root echo "<li><a href='$item->url'>$item->title</a>"; if ($item->numChildren(true)) { // check if this item has children echo "<ul>"; foreach($item->children as $sub_item) { // loop through the children of each item echo "<li><a href='$sub-item->url'>$sub_item->title</a></li>"; } echo "</ul>"; } echo "</li>"; } echo "</ul>"; For more levels, you could keep adding loops inside loops, but then, it would make more sense to make a recursive function (a function that calls itself while there still are children). One more thing. In your code you add the id for the current page like this: if($child->id == $page->rootParent->id) { // this $child page is currently being viewed (or one of it's children/descendents) // so we highlight it as the current page in the navigation echo "<li><a href='$child->url' id='current'>$child->title</a></li>"; } else { echo "<li><a href='$child->url'>$child->title</a></li>"; } You can avoid repeating code by doing this instead: if($child->id == $page->rootParent->id) { $current = ' class="current"'; } else { $current = ''; } echo "<li><a href='$child->url'{$current}'>$child->title</a></li>"; Or, more compact: $current = $child->id == $page->rootParent->id ? ' class="current"' : ''; echo "<li><a href='$child->url'{$current}'>$child->title</a></li>"; You can also replace $child->id == $page->rootParent->id by $item == $page for the current page and use rootParent to give the class to the parent item only1 point
-
1 point
-
AFAIK this is not true; you can just create a field and use type Selector from the dropdown; there shouldn't be any extra steps needed. @Ivan Gretsky - maybe you didn't install the module?1 point
-
<?php class DuplicateArticles extends WireData implements Module { public static function getModuleInfo() { return array( 'title' => 'Duplicate Articles When Created In English To All Translations', 'version' => 1, 'summary' => 'Module to create duplicate of English (master) articles as pages in every translated language.', 'singular' => true, 'autoload' => true, ); } public function init() { $this->pages->addHookAfter('added', $this, 'duplicate'); } public function duplicate($event) { $page = $event->arguments[0]; // Only duplicate pages under /articles/ if ($page->parent_id == 1023) { $a = new Page(); $a->template = 'article_french'; $a->parent = wire('pages')->get('/fr/articles/'); $a->name = $page->name; $a->title = "{$page->title} (awaiting translation)"; $a->status = Page::statusUnpublished; $a->save(); $b = new Page(); $b->template = 'article_spanish'; $b->parent = wire('pages')->get('/es/articles/'); $b->name = $page->name; $b->title = "{$page->title} (awaiting translation)"; $b->status = Page::statusUnpublished; $b->save(); $c = new Page(); $c->template = 'article_german'; $c->parent = wire('pages')->get('/de/articles/'); $c->name = $page->name; $c->title = "{$page->title} (awaiting translation)"; $c->status = Page::statusUnpublished; $c->save(); $d = new Page(); $d->template = 'article_russian'; $d->parent = wire('pages')->get('/ru/articles/'); $d->name = $page->name; $d->title = "{$page->title} (awaiting translation)"; $d->status = Page::statusUnpublished; $d->save(); $e = new Page(); $e->template = 'article_korean'; $e->parent = wire('pages')->get('/ko/articles/'); $e->name = $page->name; $e->title = "{$page->title} (awaiting translation)"; $e->status = Page::statusUnpublished; $e->save(); } } } Ok my first module... and it works! Woah. I'm only showing 5x languages above. Eventually there will be 12. Is 12x actions on a page save okay? So now I need to figure out... - More elegant way of creating each new page - there's a lot of duplicated code - A way of deleting the translated pages if the English is deleted - A way of pre-filling a pagefieldtype with the English page - this pagefieldtype is to to explicitly set the related English version to the translated version. I tried adding... $a->id = $page->related_page_language->id; But that doesn't do anything. Anyone know how I might achieve this?1 point
-
Greetings Everyone, A friend just sent me this "data video," and I find it to be an amazing example of bringing data to life (or death in this case). Take a look... https://www.facebook.com/kulturologia/videos/825181334197148/?fref=nf Thanks, Matthew1 point
-
This is getting really really great tool for editing, import and now export, too....tell me when you "run slower" forward...that i could translate the missing things to german as well. Best regards mr-fan1 point
-
I made this into a blank site profile. Download and instructions here. Tested on a new PW install and it is working fine. Maybe some of you want to test it in other environments and let me know if I need to amend the README. Thank you.1 point
-
// Skip the label as long as it's blank $submit->set('skipLabel', Inputfield::skipLabelBlank);1 point
-
Tom, that sounds like an amazing project on any CMS. Would love to see a case study or some more in depth details once it's live. Goo luck with the upcoming launch.1 point
-
I have no idea to be honest. Works fine here. But I'm not using InputfieldImage but InputfieldFile.1 point
-
I'm trying to get a image upload working with the form api. $field = $modules->get("InputfieldImage"); $field->attr('id+name','images'); $field->required = 0; $field->destinationPath = $config->uploadTmpDir; $field->extensions = "jpg jpeg gif png"; $field->maxFilesize = 2*1024*1024; $field->maxFiles = 1; $field->skipLabel = Inputfield::skipLabelBlank; $form->append($field); But if I call $form->processInput($input->post); I get this error: Error: Exception: Nicht zulässiges Bild (in /Users/Benni/Projekte/A-06-2014_HONourables/www2/wire/modules/Inputfield/InputfieldFile/InputfieldFile.module line 282) or with InputfieldFile Error: Exception: New page '/mitglieder/postfach/conversation-2014-09-06-10-59/' must be saved before files can be accessed from it (in /Users/Benni/Projekte/A-06-2014_HONourables/www2/wire/core/PagefilesManager.php line 240) I don't understand why this is trying to create a page in this location, which is the location of the page, which shows the form. The file is supposed to be for a page further down the hierarchy. Also the only template allowed as child of "postfach" doesn't even have a image field which could serve as temporary storage. I could use own upload processing, but I would much rather stay consistent with the form api.1 point
-
Don't Show API Form Labels (If I may add this here for the sake of completeness.) I have been looking for a way to leave the label out of the markup that does not involve recreating a module (a silly thing to do). The solution we have been using up until this point was a blank label. (Resulting in unnecessary markup and a negative margin.) However curiosity took me to the Inputfield module. Hey great job on these fields BTW. Reading the file I came across these options. const skipLabelNo = false; // don't skip the label at all (default) const skipLabelFor = true; // don't use a 'for' attribute with the <label> const skipLabelHeader = 2; // don't use a ui-widget-header label at all const skipLabelBlank = 4; // skip the label only when blank // wire/core/Inputfield.php Found in: in Inputfield.php The best solution I found to use this in a form builder. (I would like to credit this to somma's comment on checkbox-other-text-in-header-than-label-text) //controller.php $submit = $modules->get("InputfieldSubmit"); $submit->skipLabel = Inputfield::skipLabelBlank; //HERE IS THE SOLUTION! $submit->attr("value","SUBMIT"); $submit->attr("id+name","submit"); $submit->attr("class","button"); $form->append($form_submit); Thank you Somma! Thank you Ryan!1 point
-
You guys got me curious about PBCKCode, so I tried to install it here. Seems to work nicely. Not sure if this helps, but here's how I installed it. I downloaded the ZIP from here then extracted the contents to /site/modules/InputfieldCKEditor/ckeditor-4.1.2/plugins/pbckcode/. Then I went and edited my 'body' field and added a line for "pbckeditor" to the toolbar, and another for the "extra plugins". Then in "Extra Allowed Content", I added: "pre[class](*)". See the attached screenshot of my config screen for CKEditor. I opted not to keep the "data-pbcklang" attribute that it adds to the <pre> tag. Though I'm sure HTMLPurifier would strip that one out anyway. I figured that wasn't necessary since I already had a class tag identifying the language.1 point
-
Kyle, I pointed you to Soma's Gist that has multiple examples. Am I missing something here? Have a look at these... https://gist.github.com/somatonic/5236008#file-form-php-L88 https://gist.github.com/somatonic/5233338 (scroll all the way down to the next file as well - https://gist.github.com/somatonic/5233338#file-form-upload-php-L30) Edit: More links: http://processwire.com/talk/topic/2597-multiple-image-bug-when-using-api-resolved/ http://processwire.com/talk/topic/1530-setting-image-description-with-multiple-image-upload/ http://processwire.com/talk/topic/3105-create-pages-with-file-upload-field-via-api/page-2 http://processwire.com/talk/topic/3134-basic-image-file-upload/ http://processwire.com/talk/topic/2217-user-generated-content-with-images/ Google search works better than the Forum search1 point
-
So the lesson to be learned here, is /wire/modules/Inputfield/ is my friend. I need to remember to look there before asking my silly questions. Thanks Soma!1 point
-
You can use the InputfieldMarkup to add custom markup. $field = $modules->get("InputfieldMarkup"); $field->markupText = "<p>your html string here</p>";1 point
-
Yeah this should work. I figured out how you could add a image and get resized with the InputfieldImage you have. Having this as setting $field->maxWidth = 100; $field->maxHeight = 100; Then when adding the image to page field: // create new page image first $img = new PageImage($uploadpage->images, $upload_path . $file); // add it to page as usual $uploadpage->images->add($img); // trigger the image max size sizing $form->get("images")->fileAdded($img);1 point
-
Trying this to no avail. $field = $modules->get("InputfieldImage"); $field->label = " "; $field->required = 0; $field->maxFilesize = 2*1024*1024; $field->description = "Upload Photo"; $field->attr("name+id",'profile_photo'); $field->destinationPath = $upload_path; $field->maxWidth = 100; $field->maxHeight = 100; $form->add($field); For the sake of seeing an easy result, I set it low (100). Upload happens fine. Just no resize. Also tried as: $field->maxWidth = "100"; Still no likey.1 point
-
Thanks for all the suggestions. ProcessWire certainly has an active and helpful community behind it! Cheers1 point
-
Ups, thanks diogo. I think it's one of those afterwards adding stuff errors. Strange nobody noticed it earlier I corrected it. I think you could use the markup inputfield (InputfieldMarkup) to add an error inside the form, maybe right before or after the fields. IF you don't add a string value to the field it won't show anything. But if you give it an error it should display it. Or use custom code to validate and add it before the form like diogo suggested. I haven't tried to, but I think it's also possible to add the error to the form itself. $form->error("Hey somethings wrong");1 point
-
first of all, @soma, when trying this I noticed that you have a problem in your hotmail example, because you are adding the error to the email value and not the object itself. You should change it to this instead: $emailfield = $form->get("email"); $vemail = $email->value; if($vemail && (strpos($vemail,'@hotmail') !== FALSE)){ // attach an error to the field // and it will get displayed along the field $emailfield->error("Sorry we don't accept hotmail addresses for now."); } (new code editing of the forum is great ) --- @david, I wouldn't use a hidden field only for printing an error... If you don't mind having the error outside the form, you can do simply something like this: if(your check) { $out .= "<p>Please fill one of those three</p>"; $out .= $form->render(); } if you really want to put the error inside the form, and between elements (alert: I will be a bit creative here because I don't really know how to change the render() method), I would suggest that you use a php dom parser (yep, creative, i told you). I tried this one http://simplehtmldom.sourceforge.net by putting it on my templates folder and changing it's extension to .inc and including it on my template with include('simple_html_dom.inc');. You would be able to do what you want by writing something like this inside your error check conditional: if(your check) { $out = str_get_html($out); //get the fielset by it's id $fieldset = $out->find('fieldset#id'); // prepend the message to the fieldset $fieldset->innertext = '<p class="error">Please, fill one of these three</p>' . $fieldset->innertext; echo $out; }1 point
-
Haven't read that well. Ok, this is kinda hard to make it short, there's many way to archive this in different levels. Are those users public-registered users or trusted users you give explicit accounts? Just to give the most restricted, just front-end users: Create appropriate roles or permissions. Like a "frontend_editor" Role and only add page view permission. You give only guest and this new role to the users. When they login via backend they won't see anything and get redirected to front-page. Voila. In your templates and modules you check for the Role the user if($user->hasRole("frontend_editor")){ // do stuff } else { // do other stuff } Edit: To give access to only certain field to edit. Well since you only have a front-end user with no access to anything, you control it via code in template. And my examples above shows a "$ignore_fields" array you could choose to ecxlude certain fields as you create the form this is simple. But anything possible in PW. There's a module that enables per field limit access by Ryan http://modules.proce...eld-permission/ might be something to try. Don't know if it works with the form rendering method here. To restrict certain users to pages. Since need to know which pages a user has you can add a page field to the user template, so you can add pages a user can edit by editing it's profile. Then you can check in your front-end code if a page he wants to edit is in his added pages. For adding pages you'll have to have to parent page field or something. // does the page field contain the page he wants to edit? if($user->editable_pages->has($editpage)){ // do edit form stuff } Or just use one page that is the parent of a branch he can "work". Use this to redirect the user to his page and do stuff and always check if the user has the rights when you do something. /Just to give some examples1 point
-
What do you want to archive by doing this? For a public form? Or for logged in users to edit a page in the frontend? You could, but not all fields are suited for front-end, you'll have to also include all css, js and js configs for special fields like page asm selects and file uploads. An example that takes this approach (without special fields) is the http://modules.processwire.com/modules/form-template-processor/1 point
-
WillyC is right! How could I missed it So you can do: $form->setMarkup(array( 'list' => "<div {attrs}>{out}</div>", 'item' => "<div {attrs}>{out}</div>" ));1 point
-
Thanks for your reply. I have now managed to get the datePicker working. I am still struggling with the style since even though I put the link to the stylesheet, it doesn't seem to work... Anyway, I'll look closer later... Looks like I have to link to several stylesheets... (I told you I'm no professional developper...) Just a quick note : you wrote : wire/core/Inputfield/InputfieldDatetime/InputfieldDatetime.js . I found the file in wire/modules/Inputfield... Anyway. Thanks again.1 point
-
1 point
-
This is a field that requires additional stuff thats why it doesn't work. It would work if you include jQuery UI (with js and css) and to init the datepicker to the input you either do it by yourself with a js script or you can use the wire/modules/Inputfield/InputfieldDatetime/InputfieldDatetime.js. Depending on the jQuery UI theme you include, your form elements will get also styled. But you can roll your own or overwrite some stuff. Not sure what the best way would be for you but there are several.1 point
-
Thanks a lot for these indications. It helps me a lot, even though I'm a little stuck on one thing : my form is OK, but I'm trying to use a datepicker in one field... is this possible? Here's where I am : I changed this part of Soma's code // you get the idea $field = $modules->get("InputfieldPassword"); $field->label = "Passwort"; $field->attr("id+name","pass"); $field->required = 1; $form->append($field); with // you get the idea $field = $modules->get("InputfieldDatetime"); $field->label = "Date"; $field->attr("id+name","date"); $field->required = 1; $form->append($field); And tried to play around with $field->datepicker = 1; ...But I have to admit I don't really understand what I'm doing and I just know this doesn't work... I've spent quite a few hours on that (don't laugh ;-)) and if one of you can give me a hint, I'd greatly appreciate! Thanks !1 point
-
This is really interesting stuff and I'm learning so much from it. I've already tested Soma's code and it works very well. Is there a way of configuring $form->render() so that it outputs different html (divs for ul/li etc.)?1 point
-
Great tutorial Soma! This is the best summary of using PW's Inputfields that I've seen. I noticed you did $field->attr('id+name', 'email') so just wanted to explain what that is for those that may be unsure of the syntax. That syntax is basically saying to set the 'id' and 'name' attribute to have the 'email'. While every field needs a 'name' attribute (like in HTML) the 'id' attribute is optional… if you don't assign an id attribute, PW will make one up. If you intend to custom style a field with CSS or target it from javascript, then it's best to assign your own 'id' attribute. Otherwise, it doesn't matter. // this… $field->attr('id+name', 'email'); // …is the same as: $field->attr('id', 'email'); $field->attr('name', 'email'); // …as is this (direct reference): $field->id = 'email'; $field->name = 'email'; The advantage of using the attr() function over direct reference is that attr() can't ever collide with other Inputfield properties that might have the same name as a field attribute. It's basically your way of saying "this should definitely be an HTML attribute and not anything else." For recognized attributes like 'name' or 'value' it doesn't matter what syntax you use because an Inputfield already knows 'name' and 'value' are standard HTML attributes. But if you needed to add a custom attribute like "data-something", well then you'd definitely want to use the attr() method of setting. That attr() method should only be used for things that would actually be HTML attributes of the <input>, because they will literally end up there. So if you do an $field->attr('label', 'Hello'); you'll end up with an <input label='Hello'> in the markup, which is obviously not something that you want. That's why you assign a non-attribute property like 'label' or 'description' directly, like: $field->label = 'Something'; Last note about $attr() is that it can be used for both setting and getting attributes: $field->attr('value', 'something'); echo "The field's value is: " . $field->attr('value'); // same as: $field->value = 'something'; echo "The field's value is $field->value"; To extend your example, lets say that you wanted the 'email' and 'password' fields in a fieldset titled "About You". You would create the fieldset, and then add/append the fields to the $fieldset rather than the $form. Then you'd add the $fieldset to the $form: $fieldset = $modules->get('InputfieldFieldset'); $fieldset->label = 'About You'; $field = $modules->get("InputfieldEmail"); $field->label = "E-Mail"; $field->attr('id+name','email'); $field->required = 1; $fieldset->append($field); // append the field $field = $modules->get("InputfieldPassword"); $field->label = "Password"; $field->attr("id+name","pass"); $field->required = 1; $fieldset->append($field); $form->append($fieldset); Or lets say that you wanted those 'email' and 'password' fields to be each in their own column so that are next to each other horizontally rather than vertically. You would assign the 'columnWidth' property to both the email and password fields. In this case, we'd give them both a value of 50 to say that we want them to be a 50% width column: $field->columnWidth = 50; To jump out of tutorial mode and into idea mode: lately I've been thinking that PW should have a YAML to Inputfields conversion tool in the core (something that would be pretty easy to build), so that one could define a form like this: And create it like this (where $yaml is the string above above): $form = $modules->get('InputfieldForm'); $form->load($yaml); echo $form->render();1 point