Jump to content

[Solved] Add custom field to template


nabo
 Share

Recommended Posts

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

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

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

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;
    }

 

  • Like 3
Link to comment
Share on other sites

Thanks @kixe. New field is perfectly loaded after tags in advanced tab.

But when I try to save I've got an error
Error: 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

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"});
			}
		}
	}
}

 

  • Like 4
Link to comment
Share on other sites

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"});
                }
            }
        });

 

  • Like 4
Link to comment
Share on other sites

4 hours ago, nabo said:

But when I try to save I've got an error
Error: 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. 
 

  • Like 1
Link to comment
Share on other sites

  • 6 months later...

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

  • 1 year later...
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

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
 Share

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...