nabo Posted November 4, 2016 Share Posted November 4, 2016 Hello I would like to add a custom field to template to extend a functionality of MarkupSEO module. In that module there's a very nice setting that lets you configure a title structure for <title> tag, for example {title}, {sitename} etc. But this configuration is valid for every template. I thought that it would be better if I can configure this setting by template: in fact for product template I could use {title}, {category} and so on to create a dynamic title. I began to write a module, but I stopped early because of an error. I think this is why I am at the beginning of PW experience and I missed something. I was inspired by this module https://github.com/BitPoet/TemplateParent... the goal is to have two InputfieldTextLanguage (title and description) under the Advanced TAB in Edit Template. Any idea or suggestion are appreciated, thanks! Link to comment Share on other sites More sharing options...
kixe Posted November 5, 2016 Share Posted November 5, 2016 @nabo Welcome to the forum. You need to hook in ProcessTemplate::buildEditForm. More about hooks:http://processwire.com/api/hooks/ 1 Link to comment Share on other sites More sharing options...
nabo Posted November 7, 2016 Author Share Posted November 7, 2016 Thank you @kixe! I've seen that hook and I begun to code a little snippet... public function init() { $this->addHookAfter("ProcessTemplate::buildEditForm", $this, "appendFieldToForm"); } public function appendFieldToForm($event) { $frm = $event->return; $field = $this->modules->get("InputfieldTextLanguage"); $field->attr('name', 'seo_rule'); $field->attr('value', $template->seo_rule); $field->label = $this->_('Seo rule'); $field->description = $this->_('If you want to add a custom rule to MarkupSEO'); // Description for field tags $field->notes = $this->_('To define a variable use {title} syntax'); $form = $frm->find('id=advanced')->first(); $form->insertAfter($field,"tags"); } But when I try to install, viewing a template return me an error on line 35 $field->attr('name', 'seo_rule').... maybe because field doesn't exist?! Don't know how to create Link to comment Share on other sites More sharing options...
kixe Posted November 7, 2016 Share Posted November 7, 2016 From the first view your code has some issues: 1. The variable $template is not defined. This one should work: $template = $event->argument[0]; 2. You cannot use InputfieldTextLanguage here. You need to use InputfieldText and than loop the languages. $languages = $this->wire('languages'); $field->attr('value', $template->seo_rules); if($languages) { $field->useLanguages = true; foreach($languages as $language) $field->set('value' . $language->id, $template->get('seo_rules' . $language->id)); } 3. As far as I know 2nd Argument of function insertAfter() should be an object of type Inputfield you are using a string. 4. in the end you need to overwrite $event->return otherwise there is no change. If I find some time I will have a deeper look. Link to comment Share on other sites More sharing options...
nabo Posted November 7, 2016 Author Share Posted November 7, 2016 thanks @kixe as you can see my code is very bad, thanks for suggestions Link to comment Share on other sites More sharing options...
kixe Posted November 7, 2016 Share Posted November 7, 2016 Try this: public function init() { $this->addHookAfter("ProcessTemplate::buildEditForm", $this, "appendFieldToForm"); $this->addHookBefore("ProcessTemplate::executeSave", function($event) { $event->object->template->set('seo_rules', $this->input->post->seo_rules); $languages = $this->wire('languages'); if($languages) { foreach($languages as $language) { $event->object->template->set('seo_rules'.$language->id, $this->input->post->{"seo_rules__$language->id"}); } } }); } public function appendFieldToForm(HookEvent $event) { $languages = $this->wire('languages'); $template = $event->arguments[0]; $form = $event->return; $field = $this->modules->get("InputfieldText"); $field->attr('id+name', 'seo_rules'); $field->attr('value', $template->seo_rules); if($languages) { $field->useLanguages = true; foreach($languages as $language) $field->set('value' . $language->id, $template->get('seo_rules' . $language->id)); } $field->label = $this->_('Seo rule'); $field->description = $this->_('If you want to add a custom rule to MarkupSEO'); // Description for field tags $field->notes = $this->_('To define a variable use {title} syntax'); $form->insertAfter($field, $form->tags); $event->return = $form; } 3 Link to comment Share on other sites More sharing options...
nabo Posted November 8, 2016 Author Share Posted November 8, 2016 Thanks @kixe. New field is perfectly loaded after tags in advanced tab. But when I try to save I've got an errorError: Uncaught Error: Call to a member function set() on null on line $event->object->template->set('seo_rules', $this->input->post->seo_rules); Error: Uncaught Error: Call to a member function set() on null in Link to comment Share on other sites More sharing options...
nabo Posted November 8, 2016 Author Share Posted November 8, 2016 Solved!!! Hope can be useful This is the class class SeoTemplate extends WireData implements Module { public static function getModuleInfo() { return array( "title" => "SeoTemplate", "summary" => "Module for add seo_rules field to template.", "version" => "0.0.1", "autoload" => true ); } public function init() { $this->addHookAfter("ProcessTemplate::buildEditForm", $this, "appendFieldToForm"); $this->addHookBefore("ProcessTemplate::executeSave", $this, "saveSeoRuleField"); } public function appendFieldToForm(HookEvent $event) { $languages = $this->wire('languages'); $template = $event->arguments[0]; $form = $event->return; $field = $this->modules->get("InputfieldText"); $field->attr('id+name', 'seo_rules'); $field->attr('value', $template->seo_rules); if($languages) { $field->useLanguages = true; foreach($languages as $language) $field->set('value' . $language->id, $template->get('seo_rules' . $language->id)); } $field->label = $this->_('Seo rule'); $field->description = $this->_('If you want to add a custom rule to MarkupSEO'); $field->notes = $this->_('To define a variable use {title} syntax'); $form->insertAfter($field, $form->tags); $event->return = $form; } public function saveSeoRuleField($event) { $template = $this->templates->get($this->input->post->id); $template->set('seo_rules', $this->input->post->seo_rules); $languages = $this->wire('languages'); if($languages) { foreach($languages as $language) { $template->set('seo_rules'.$language->id, $this->input->post->{"seo_rules__$language->id"}); } } } } 4 Link to comment Share on other sites More sharing options...
adrian Posted November 8, 2016 Share Posted November 8, 2016 Nice work! Just in case you would find it cleaner, you can use this version in your site/init.php file rather than setting up an actual module. Sometimes this approach is nicer than having lots of different little helper modules. $this->addHookAfter("ProcessTemplate::buildEditForm", function(HookEvent $event) { $languages = $this->wire('languages'); $template = $event->arguments[0]; $form = $event->return; $field = $this->modules->get("InputfieldText"); $field->attr('id+name', 'seo_rules'); $field->attr('value', $template->seo_rules); if($languages) { $field->useLanguages = true; foreach($languages as $language) $field->set('value' . $language->id, $template->get('seo_rules' . $language->id)); } $field->label = $this->_('Seo rule'); $field->description = $this->_('If you want to add a custom rule to MarkupSEO'); $field->notes = $this->_('To define a variable use {title} syntax'); $form->insertAfter($field, $form->tags); $event->return = $form; }); $this->addHookBefore("ProcessTemplate::executeSave", function() { $template = $this->templates->get($this->input->post->id); $template->set('seo_rules', $this->input->post->seo_rules); $languages = $this->wire('languages'); if($languages) { foreach($languages as $language) { $template->set('seo_rules'.$language->id, $this->input->post->{"seo_rules__$language->id"}); } } }); 4 Link to comment Share on other sites More sharing options...
kixe Posted November 8, 2016 Share Posted November 8, 2016 4 hours ago, nabo said: But when I try to save I've got an errorError: Uncaught Error: Call to a member function set() on null Error: Uncaugh Error Call to a member function set() on null in I didn't know that you need to extend the WireData class. Extending ProcessTemplate this shouldn't happen. 1 Link to comment Share on other sites More sharing options...
nabo Posted November 8, 2016 Author Share Posted November 8, 2016 NP @kixe, thanks to you! Link to comment Share on other sites More sharing options...
Jonathan Lahijani Posted May 23, 2017 Share Posted May 23, 2017 On 11/7/2016 at 9:54 AM, kixe said: Try this: $form->insertAfter($field, $form->tags); Shouldn't it actually be this? $form->insertAfter($field, $form->getChildByName('tags')); Link to comment Share on other sites More sharing options...
kixe Posted May 24, 2017 Share Posted May 24, 2017 Both is possible since InputfieldWrapper::get() calls InputfieldWrapper::getChildByName() /** * assuming $form is a member of InputfieldWrapper class * the return of the following api calls are similar * if the field exists the return value is an instance of Inputfield otherwise NULL */ $form->tags; $form->get('tags'); $form->getChildByName('tags'); Link to comment Share on other sites More sharing options...
harmvandeven Posted August 24, 2018 Share Posted August 24, 2018 On 11/8/2016 at 1:45 AM, nabo said: Solved!!! Hope can be useful It worked perfect for me to... for a while. Somehow my custom fields remain empty (I think after upgrading my PW version to 3.0.98). I can still see/use the old values, but when I save a template all the predefined custom fields are cleared and remain empty. Is anyone experiencing the same thing? Nevermind... it was my own silly mistake. I only saved values when they returned true on isset(). isset($this->input->post->{$key}) Somehow the isset above always returns false even though echo $this->input->post->{$key}; returns the actual value. Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now