Panel hooks from loop fails

i tried hooking the panel using a for loop. but it did not work.

$events = ['panel.page.update', 'panel.page.delete'];
foreach ($events as $ev) {
  kirby()->hook($ev, function($obj) {
    $dir = kirby()->roots()->index() . DS . $ev.'.txt';
    file_put_contents($dir, time());
  });
}

once i unroll the loop it does work. like this.

  kirby()->hook('panel.page.update', function($obj) {
    $dir = kirby()->roots()->index() . DS . $ev.'.txt';
    file_put_contents($dir, time());
  });

what am i missing?

Your function doesn’t have access to the $ev variable:

$events = ['panel.page.update', 'panel.page.delete'];
foreach ($events as $ev) {
  kirby()->hook($ev, function($obj) use($ev) {
    $dir = kirby()->roots()->index() . DS . $ev.'.txt';
    file_put_contents($dir, time());
  });
}

I don’t know if that works (could be that use doesn’t preserve the state and you will get a value of panel.page.delete for both) but you could try that.

BTW: What do you want to with the hook?

actually i am trying to hook to all available events and log that something happend. my log function is based on the uniform log action.

function hook_log($obj) {
  if(is_a($obj, 'Page')) {
    // for some templates
    if( substr($obj->template(), 0, 4) == 'obj-' || 
        substr($obj->template(), 0, 3) == 'db-' || 
        in_array($obj->template(), ['home', 'site'] )
        ) {
      Hlprs::log($ev, [
        'autoid' => $obj->autoid()->exists() ? $obj->autoid() : false,
        'uri' => $obj->uri(),
        'site.user' => site()->user() ? site()->user()->username() : false,
      ]);
    }
  } else if (is_a($obj, 'File')) {
    Hlprs::log($ev, [
      'uri' => $page->uri(),
      'siteuser' => site()->user() ? site()->user()->username() : false,
    ]);
  } else if (is_a($obj, 'User')) {
    Hlprs::log($ev, [
      'uri' => $obj->uri(),
      'username' => $obj->username(),
      'siteuser' => site()->user() ? site()->user()->username() : false,
    ]);
  }
}

used like this. now you see my intention to use the loop.

kirby()->hook('panel.page.create', function($page) {
  hook_log($page);
});

kirby()->hook('panel.file.replace', function($file) {
  hook_log($file);
});

kirby()->hook('panel.user.update', function($user) {
  hook_log($user);
});

the log function is defined in Hlprs class.

    public static $LOG_FOLDER = DS.'logs'.DS;
    public static $LOG_EXTENSION = '.log';
    public static function log($fileURI, $arr) {
	$root = kirby()->roots()->index();
	// based on uniform action 'log'
	$filepath = $root.Hlprs::$LOG_FOLDER.str::lower(str_replace('.', '-', $fileURI)).Hlprs::$LOG_EXTENSION;
	$data = '['.date('c').'] '.visitor::ip().' '.visitor::userAgent();
	foreach ($arr as $key => $value) {
        if (is_array($value)) {
            $value = implode(', ', array_filter($value, function ($i) {
                return $i !== '';
            }));
        }
        $data .= "\n{$key}: {$value}";
    }
    $data .= "\n\n";
    $success = file_put_contents($filepath, $data, FILE_APPEND | LOCK_EX);
    if(!$success) {
    	throw new Exception('ERROR: failed to write to log');
    }
    return $success;
    
}

the panel progress bar is incredibly slow at localhost. so maybe its related to this?

i took debugging inspriation from here: Debugging hooks?

but my problem seems to be with update in general. once i create a hook for panel.page.update the panel progress bar goes into a crawl. the hooked function can even be totally empty.

i am using most current kirby installation (CLI). mac, mamp pro.

tried pushing to webserver. still slow progressbar for panel.page hooks groupe. even tried clean kirby CLI installation with just adding these lines to config.php

function hook_log ($obj) {
   file_put_contents('test8.log', 'hello');
}
kirby()->hook('panel.page.update', 'hook_log');

progressbar goes to a grind.

no problems with file and user hooks btw.

writing to folder outside the /panel from hook is possible like @jenstornell did. so this does not seem to be the issue here.

 file_put_contents(kirby()->roots()->index().'/test11.log', 'hello');

i tried the clean kirby install and revisions no issue with the hooks there. i do not understand why my simple code block it.

tried same code as revisions did. no luck still slow progress bar.

$mycallback = function( $page ) {
	file_put_contents(kirby()->roots()->index().'/test14.log', 'hello');
};
kirby()->hook('panel.page.update', $mycallback );

does not seem to be a problem of file_put_contents, since copy() is slow too. even with error suppersion @.

$mycallback = function( $page ) {
   //file_put_contents(kirby()->roots()->index().'/test14.log', 'hello');
   @copy( $page->content()->root(), kirby()->roots()->index().DS.'acopy.txt' );
};

kirby()->hook('panel.page.update', $mycallback );

i think i found it.

its caused if there are two or more hooks on the same type like ‘panel.page.update’. in my original case it was autoid and my hook. in my clean install it was revisions and my hook. once there is only one hook it works fine, both of them. i created a plugin from my config.php hook but same problem.

maybe @texnixe can verify this based on her old post ?

i see why autoid from @helllicht might cause a panel.page.update loop. the plugin calls $page->update() here.

but revisions plugin does not, neither did my hook. why did there two not work well together?

It’s a bug that’s fixed on the development branch. I can’t find but it’s on Github somewhere.

this? https://github.com/getkirby/kirby/issues/451

1 Like

thx @texnixe. this fixed the issue with panel.page.update. i will search github issues next time before spending hours myself. :neutral_face:

but i still get slow progress if renaming a file. both panel.file.update and panel.file.rename are triggered. i can skip rename hook if needed but i am curious why it fails.

my logging creates a slow progress for panel.page.create too because the panel.page.update is called along with it. is writing the logfile taking to long? how are hooks triggered?
i am writing to different files for each hook so it should not be a locking issue there, right?

panel.user.create does not trigger panel.user.update. why? if panel.page.create does trigger panel.page.update, so should user.

@bnomei: I don’t quite understand what you mean. When a page/user/file etc. is created, only the panel.xxx.create hook is triggered, not the update hook?

Maybe you can add the same functions in both create and update hooks? I do something like that in my Revisions plugin.