Jump to content

Hooking into a Page field render - for all page fields


Sinmok
 Share

Recommended Posts

Hello all,

Little stuck on how to override what a field outputs when being called within a template file.

Take the following sample code inside a template:

<h1>
 <?=$page->title?>
</h1>

<div>
<?=$page->another_field?>
</div>

What I'm trying to do is analyse and potentially modifying the output of this field from within a template, using a module WITHOUT saving the page.

This is currently the code that I'm trying to run

	public function init() {
		// add a hook after each page is rendered and modify the output
		$this->addHookBefore('Page::render', $this, 'exec');
	}

	public function exec($event) {

        //Get the rendered page
	$page = &$event->object;

        if($page->template == 'admin') {
            return;
        }

        //As a test, try and modify the title field, but in the future I'll need to be able to modify any fields
        $page->set("title","A test title!");

	}

Unfortunately, this doesn't work. - The page still renders the original title within the template!

Ideally - my long term goal is to know:

  1. What the field type of the called/rendered field is
  2. The current value of this field

Any guidance is appreciated!

  • Like 1
Link to comment
Share on other sites

Works fine

$this->addHookBefore('Page::render', $this, 'renderHook');
public function renderHook($event) {
    $page = $event->object;
    if($page->template == 'admin') return;
    $page->title = "ohhhhhhh";
}

Now the rendered page has always title ohhhhhhh. But this does not change the title for page in navigation or other places.

  • Like 1
Link to comment
Share on other sites

I should have been more specific. I don't know what the field is going to be. I need to iterate over the pages fields and then make a decision based on that.

For example:

        
        $page = $event->object;

        if($page->template == 'admin') {
            return;
        }

        $fields = $page->fields;

        foreach($fields as $field){

           $this->setup($page,$field);

        }

However, within setup I try

    protected function setup($page, $field){

        if($conditional_logic){
           $page->{$field->name} = "Some other value";
        }

    }

But I get the error

Exception: Page '/test/' is not currently viewable. (in /var/www/modules/wire/modules/PageRender.module line 251)

Even though I can echo out the contents of $page->{$field->name};

Link to comment
Share on other sites

Hello all,



Ideally - my long term goal is to know:

  1. What the field type of the called/rendered field is
  2. The current value of this field

Any guidance is appreciated!

If on page render, there's no field render. Just a page and it's fields. To get fields on a page there's several methods.

Maybe the most natural and just general would be

foreach($page->fields as $f) {
    echo "Type:$f->type Name: $f->name Label: $f->label<br>";
}

$page->template->fields, $page->get("fields") etc

A more deep hook into fields would be to hook formatValue(page, field, value) of Fieldtype. It will replace every title fields rendered on page also from other pages.

$this->addHookAfter('Fieldtype::formatValue', $this, 'hookFields');

public function hookFields($event) {
    $page = $event->arguments("page");
    $field = $event->arguments("field");
    $value = $event->arguments("value");
    
    // not sure this is needed here, and won't prevent from exec in admin. You better set module config to "autoload" => "template!=admin"
    if($page->template == "admin") return; 

    if($field->name == "title"){
        $event->return = "ohhhhhhh";
    }
}

You could also just hook into specified field type like page title field

$this->addHookAfter('FieldtypePageTitle::formatValue', $this, 'hookTitle');

You can also create your own property as per HelloWorld.module. But not overwrite already existing fields.

$this->addHookProperty('Page::hello_world', $this, 'example4');

I'm not sure what you're trying to archive and if there isn't another approach, just mention ways...

I should have been more specific. I don't know what the field is going to be. I need to iterate over the pages fields and then make a decision based on that.

For example:

You asked how to modify the page title. I showed you how and it's working.

Fieldtype::formatValue will get called only when output formatting is on. And it's called when using TextFormatter modules on a field.

  • Like 1
Link to comment
Share on other sites

  • 9 months later...
  • 1 month later...

Hi, 

I was trying to show the system template on Selectorfield as asked over : https://processwire.com/talk/topic/9026-show-system-templates-on-selectorfield/

Is there a way to make a hook like this work?

public function init()
{
    $this->addHookBefore('InputfieldSelector::render', $this, 'selectorField');
}

public function selectorField($event)
{
    $inputSelector = $event->object;
    if ($event->object->name == 'field1') {
        $inputSelector->allowSystemTemplates = true;
        $event->return = $inputSelector;
        return $event->return;
    }    
}

Though I did this, it seems not working properly :( .

Link to comment
Share on other sites

There shouldn't be a need to change $event->return, as you're hooking before the function not after it. Also you don't want to replace the returned markup of InputfieldSelector::render. The option is correctly set, but it's not working for me, too.

  • Like 1
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...