Jump to content
jploch

[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?

Share this post


Link to post
Share on other sites

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

  • Like 1

Share this post


Link to post
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

Share this post


Link to post
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

Share this post


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

 

Share this post


Link to post
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 🙂

Share this post


Link to post
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?

Share this post


Link to post
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 

Share this post


Link to post
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?

Share this post


Link to post
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

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
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

Share this post


Link to post
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.

Share this post


Link to post
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

Share this post


Link to post
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);

 

Share this post


Link to post
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

Share this post


Link to post
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

Share this post


Link to post
Share on other sites
2 minutes ago, jploch said:

But this would create a <link> element right?

Yeah, you are right. Now I see what you want to do 😄 inject the CSS directly

  • Like 1

Share this post


Link to post
Share on other sites
Just now, dotnetic said:

Yeah, you are right. Now I see what you want to do 😄 inject the CSS directly

yep 😉

Share this post


Link to post
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

Share this post


Link to post
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

Share this post


Link to post
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'?

Share this post


Link to post
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

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By picarica
      Hello so am trying to make a hook so that all checkbox field is defaul;ty checked when making new page, soo i made hook in init.php and the contents are
      <?php $wire->addHookAfter("Pages::added", function($event) { $page = $event->arguments(0); // check for page template if necessary here $page->checkboxfield('check', 1); }); ?> and what i get
      which is weird because "table" is a repeat field where checkboxfield is nowhere present, but table repeat field and checkboxfield are in the same template, so why does it outputs error like that? any ideas ?
    • By Sten
      Hello
      Till now I hacked something with the twig template but it works no more with new PW versions so I look forward to create a module. I am working on a site in multiple languages : French, English, Italian, German, Spanish, Portuguese, Hebrew, Russian. The new posts are entered in any language with a field for language. Till now, I got twig files to get the translations with constants defined for each part of the pages.
      So I'd like to create a module to include theses files added according to the url /fr/en/...
      Have you some observations to do before I begin about the direction to take ?
      Thank you
    • By gebeer
      Hello all,
      wasn't sure where to put this, so it goes in General section.
      Ryan shows a hook that we can use to mirror files on demand from live server to development environment to be up to date with the files on the server without having to download complete site/assets/files folder.
      I just implemented this but had problems getting files to load from a site in development that is secured with user/password via htaccess.
      First I tried to use WireHttp setHeader method for basic authentication like this
      function mirrorFilesfromLiveServer(HookEvent $event) { $config = $event->wire('config'); $file = $event->return; if ($event->method == 'url') { // convert url to disk path $file = $config->paths->root . substr($file, strlen($config->urls->root)); } if (!file_exists($file)) { // download file from source if it doesn't exist here $src = 'http://mydomain.com/site/assets/files/'; $url = str_replace($config->paths->files, $src, $file); $http = new WireHttp(); // basic authentication $u = 'myuser'; $pw = 'mypassword'; $http->setHeader('Authorization: Basic', base64_encode("$u:$pw")); $http->download($url, $file); } } But, unfortunately this didn't work.
      So now I am using curl to do the download. My hook function now looks like this
      function mirrorFilesfromLiveServer(HookEvent $event) { $config = $event->wire('config'); $file = $event->return; if ($event->method == 'url') { // convert url to disk path $file = $config->paths->root . substr($file, strlen($config->urls->root)); } if (!file_exists($file)) { // download file from source if it doesn't exist here $src = 'http://mydomain.com/site/assets/files/'; $fp = fopen($file, 'w+'); // init file pointer $url = str_replace($config->paths->files, $src, $file); $u = 'myuser'; $pw = 'mypassword'; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_TIMEOUT, 50); // crazy high timeout just in case there are very large files curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_USERPWD, "$u:$pw"); // authentication curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); // authentication curl_setopt($ch, CURLOPT_FILE, $fp); // give curl the file pointer so that it can write to it curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); $data = curl_exec($ch); curl_close($ch); } } Now I can load files and images from the htaccess protected development server 🙂
      If anyone knows how to get this to work with WireHttp, please let me know. Thank you.
    • By Guy Incognito
      I've created a simple sports league fixture generator in a template called 'League'. Teams are added as page references then a fixture list is created as a ProFields table by hooking page save to add new rows to the table.
      The bit I need help with is that I'm trying to check a fixture doesn't already exist before adding it to the table (e.g. if a new team is added to the league). I'm trying to do this with a PW selector to filter the fixtures table and check whether Team A vs Team B already exists in the table. Then on the next line checking no fixture was found by using count().
      However as soon as I add the selector the script no longer adds any rows to the table. If I take it out, it all works fine (albeit with duplicate fixtures each time the page is saved). I've also tested the selector in a page template and it filters as expected. It's late here (UK)... I'm probably doing something stupid! Any ideas?
      <?php //Hook page save to generate league fixture lists $wire->addHookAfter("Pages::saved(template=league)", function ($event) { //Get which page has been saved $page = $event->arguments(0); $noFixturesAdded = 0; //For each team in league cycle through and add home fixtures foreach ($page->teams_in_league as $teamA) { foreach ($page->teams_in_league as $teamB) { //Check if fixture already exists $existingFixtures = $page->fixtures("team_a=$teamA,team_b=$teamB"); //Check team A is not the same as team B as you can't play yourself //Then add row to fixture table if ($teamB != $teamA && $existingFixtures->count() < 1 ) { $fixture = $page->fixtures->makeBlankItem(); $fixture->team_a = $teamA->id; $fixture->team_b = $teamB->id; $page->fixtures->add($fixture); $noFixturesAdded ++; } } } //Save updates to table $page->save('fixtures'); $message = "League saved. $noFixturesAdded new fixtures were added"; $this->message($message); });  
    • By Macaco
      It's a bilingual site. There are two pages: "Artists" and "Events" each with a "Page Reference" field connecting each other.
      - Artists has a field where one can choose events available.
      - Events has a field where you can either choose artists available or create new ones.
      The problems: 
      - When I create an "Artist" page and select events from the list, it doesn't update the collection of participating artists on the "Event" page.
      - When I create an artist from the "Event" page. The field 'artist page > settings > language' is not "Active" for the second language.  When the artist page is created manually,"Active" is on by default.
      I know this all have to do with hooks, but I'm don't fully understand the logics.
×
×
  • Create New...