Jump to content

[SOLVED] Hook not working inside module


Recommended Posts

Hi folks,
i try to use a hook to change some markup inside admin, this hook works fine inside a ready.php file, but its not working inside my module:

<?php

namespace ProcessWire;

class InputfieldPageTableExtendedGrid extends InputfieldPageTable {

    public static function getModuleInfo() {
        return array(
            'title' => __('Inputfield for PageTableExtendedGrid', __FILE__), // Module Title
            'summary' => __('Adds Inputfield for PageTableExtendedGrid', __FILE__), // Module Summary
            'version' => 233,
            'requires' => array('FieldtypePageTableExtendedGrid'),
            'permanent' => false,
        );
    }

public function ready() {
    $this->addHookAfter('Page::render', function($event) {
	$value  = $event->return; // Return Content
	$style = "<style type='text/css'>". $this->pages->get((int) wire('input')->get('id'))->style ."</style>"; // Add Style inside bottom head
	$event->return = str_replace("</head>", "\n\t$style</head>", $value); // Return All Changes
     });
  }
  }

whats wrong here?

Link to comment
Share on other sites

37 minutes ago, dotnetic said:

Have you tried it in the init method instead? If not, try it.

I already tried that, but no success ?
It's strange because the hook works in ready.php or admin.php

Link to comment
Share on other sites

Try this:

$this->wire()->addHook('ProcessWire::ready', function($event) {
    $event->page->addHookAfter('render', function($event) {
        $value  = $event->return; // Return Content
        $style = "<style type='text/css'>". $this->pages->get((int) wire('input')->get('id'))->style ."</style>"; // Add Style inside bottom head
        $event->return = str_replace("</head>", "\n\t$style</head>", $value); // Return All Changes
    });
});

inside your module's init() method.

  • Like 2
Link to comment
Share on other sites

Where do you want to use the additional CSS, in a page edit form?

if so, you could use this code and edit it to use your GET variables

 public function init()
  {
    $this->addHookBefore('ProcessPageEdit::buildForm', $this, 'addAssets');
}

protected function addAssets(HookEvent $event)
  {
    $this->config->styles->add($this->config->urls->templates . "css/your.css?v=2");
  }

 

Link to comment
Share on other sites

13 minutes ago, dotnetic said:

Where do you want to use the additional CSS, in a page edit form?

if so, you could use this code and edit it to use your GET variables


 public function init()
  {
    $this->addHookBefore('ProcessPageEdit::buildForm', $this, 'addAssets');
}

protected function addAssets(HookEvent $event)
  {
    $this->config->styles->add($this->config->urls->templates . "css/your.css?v=2");
  }

 

I work on a pagebuilder module based on PageTable, for this I need to save dynamically added styles to a field on the page.
The styles in the field (field called style) need to be added before page renders. I could add these styles back with JS, but than the page jumps when loading. I could also try to write these styles into a file with javascript, but would like to avoid that complexity and instead add the styles in a <style> tag. Hope that makes sense ?

Link to comment
Share on other sites

1 minute ago, jploch said:

I could also try to write these styles into a file with javascript, but would like to avoid that complexity and instead add the styles in a <style> tag.

What I posted above should allow you to do that. Did you try?

Link to comment
Share on other sites

18 minutes ago, adrian said:

Try this:


$this->wire()->addHook('ProcessWire::ready', function($event) {
    $event->page->addHookAfter('render', function($event) {
        $value  = $event->return; // Return Content
        $style = "<style type='text/css'>". $this->pages->get((int) wire('input')->get('id'))->style ."</style>"; // Add Style inside bottom head
        $event->return = str_replace("</head>", "\n\t$style</head>", $value); // Return All Changes
    });
});

inside your module's init() method.

no luck with this either. I tried inside init and ready function. There seems to be something wrong with how I setup my module, because the hook works inside other modules 

Link to comment
Share on other sites

Where do you use the CSS?

In the modules config page? Or does the module hook into a normal page that is being edited in the admin? Or do you have a custom module output inside the admin?

Link to comment
Share on other sites

1 minute ago, dotnetic said:

Where do you use the CSS?

In the modules config page? Or does the module hook into a normal page that is being edited in the admin?

normal page, where the pagetable is rendered

Link to comment
Share on other sites

I think it might be because you are extending InputfieldPageTable rather than Wire or WireData. Sorry, I have to run now, but maybe that will get you on the right track. Usually with a custom inputfield you just need a css file named to match the class of the module and it will be automatically loaded, eg InputfieldPageTableExtendedGrid.css

  • Like 2
Link to comment
Share on other sites

And with my function the code is inserted before the page is rendered, so no jumping should occur.

Also you use PW`s internal method for adding a stylesheet instead of something custom.

Link to comment
Share on other sites

16 minutes ago, dotnetic said:

Then the ProcessPageEdit::buildForm would be the hook for you.

I tried this with no success:

 public function ready() {
    $this->addHookAfter('ProcessPageEdit::buildForm', function($event) {
	$value  = $event->return; // Return Content
	$style = "<style type='text/css'>". $this->pages->get((int) wire('input')->get('id'))->style ."</style>"; // Add Style inside bottom head
	$event->return = str_replace("</head>", "\n\t$style</head>", $value); // Return All Changes
     });
  }

 

14 minutes ago, dotnetic said:

And with my function the code is inserted before the page is rendered, so no jumping should occur.

Also you use PW`s internal method for adding a stylesheet instead of something custom.

I know how to add styles and scripts to my module and that is working fine. However to make it work with my dynamically generated styles from Javascript I have to use the method with the style tag. 

  • Like 1
Link to comment
Share on other sites

I do understand that you want your custom styles in the head, but you can use the 

PWs method in conjunction with your code and have it dynamic:

$this->config->styles->add($this->pages->get((int) wire('input')->get('id'))->style);

 

Link to comment
Share on other sites

25 minutes ago, adrian said:

I think it might be because you are extending InputfieldPageTable rather than Wire or WireData. Sorry, I have to run now, but maybe that will get you on the right track. Usually with a custom inputfield you just need a css file named to match the class of the module and it will be automatically loaded, eg InputfieldPageTableExtendedGrid.css

This is probably it. How could I use my hooks in this case? Maybe I should just create another helper module and put the code there, but that would also add more bloat than needed

Link to comment
Share on other sites

2 minutes ago, dotnetic said:

I do understand that you want your custom styles in the head, but you can use the 

PWs method in conjunction with your code and have it dynamic:


$this->config->styles->add($this->pages->get((int) wire('input')->get('id'))->style);

 

But this would create a <link> element right?

  • Like 1
Link to comment
Share on other sites

If the hook works in ready.php but not in your module it will most likely not get called. Did you try this?

public function ready() {
  bd('fired!');
  // or die('fired'); if you are not using tracy
}

In your module? I guess it will NOT fire and I guess the reason is that your module does simply not get loaded in your request. An Inputfield does for example never get loaded when visiting any frontend page or for example when viewing the page tree in the backend. It does only get loaded in ProcessPageEdit!

So the first step is to find out when your ready() method in your module gets fired and when not.

ready.php loads on every request. Inputfields do also have the renderReady() method that get called even when the Inputfield is loaded via AJAX. Is your Inputfield collapsed somehow?

  • Like 2
Link to comment
Share on other sites

3 hours ago, bernhard said:

If the hook works in ready.php but not in your module it will most likely not get called.

I could be too tired to wrap my head around this properly, but it seems to me that your module's init/ready is going to be called after the (admin) page::render method is called, which would explain why it has no effect at all. Your module is not autoloaded, so the init/ready should only trigger when this specific inputfield is being rendered, which is likely too late in the process.

Might be easier to go along the lines of what Adrian suggested and a) split the hook into a separate module that extends Wire, and b) make that separate module autoload (preferably with conditional autoloading, i.e. when the template is admin or something) ?

(Note: making the Inputfield module itself autoloading should probably work too, but this way you'll end up loading some unnecessary baggage even when it's not necessarily needed.)

  • Like 2
Link to comment
Share on other sites

14 hours ago, teppo said:

I could be too tired to wrap my head around this properly, but it seems to me that your module's init/ready is going to be called after the (admin) page::render method is called, which would explain why it has no effect at all. Your module is not autoloaded, so the init/ready should only trigger when this specific inputfield is being rendered, which is likely too late in the process.

Might be easier to go along the lines of what Adrian suggested and a) split the hook into a separate module that extends Wire, and b) make that separate module autoload (preferably with conditional autoloading, i.e. when the template is admin or something) ?

(Note: making the Inputfield module itself autoloading should probably work too, but this way you'll end up loading some unnecessary baggage even when it's not necessarily needed.)

Thanks @teppo! This was it! I ended up putting my hook inside the Fieldtype Module instead of the Inputfield Module and made the Fieldtype Module autoload with 'autoload' => 'template=admin'. This way the hook works and the Inputfield still seems to be only initialized when the corresponding field is on the page being edited is rendered. Here is my code (adapted from PageTableExtended):

<?php namespace ProcessWire;
class FieldtypePageTableExtendedGrid extends FieldtypePageTable {

        public static function getModuleInfo() {
          
                return array(
                        'title' => __('PageTable extended grid'), // Module Title
                        'summary' => __('Extends PageTable entries for rendering in admin', __FILE__), // Module summary
                        'version' => 233,
                        'requires' => array('FieldtypePageTable'),
                        'installs' => 'InputfieldPageTableExtendedGrid',
                        'autoload' => 'template=admin',
                        );
        }

        public function init() {
                parent::init();
          
        }

        public function ready() {
          parent::ready(); 
          if ($this->pages->get((int) wire('input')->get('id'))->style) {
            
          // add dynamically created styles from field back to document
            $this->addHookAfter('Page::render', function($event) {
            $value = $event->return; // Return Content
            $style = "<style type='text/css' class='pagegrid-styles'>
              ". $this->pages->get((int) wire('input')->get('id'))->style ."
            </style>"; // Add Style inside bottom head
            $event->return = str_replace("</head>", "\n\t$style</head>", $value); // Return All Changes
            });
            
            }
        }

        /**
         * Get the Inputfield used for input by PageTableExtended
         *
         * @param Page $page
         * @param Field $field
         * @return Inputfield
         *
         */
        public function getInputfield(Page $page, Field $field) {
                $inputfield = $this->modules->get('InputfieldPageTableExtendedGrid');
                $inputfield->attr('value', $page->getUnformatted($field->name));
                return $inputfield;
        }

}

Seems to work great, my hook only triggers when the style field is present on the page. Are there any drawbacks to this approach?
Would my field still work with frontend editor, when I do 'autoload' => 'template=admin'?

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

×
×
  • Create New...