Jump to content

addHookAfter on Pages saveReady (filling up a index(textarea) field for search) causes internal server error when trying to save the pages with the index field per api


Orkun
 Share

Recommended Posts

Hi Guys

This hook works fine. 

$this->addHookAfter('Pages::saveReady', $this, 'hookIndexingBefore');

protected function hookIndexingBefore( HookEvent $event ) {

        $page = $event->arguments("page");

        if(!$page->template->hasField("index")) return;	// no index field in this page/template
        if($page->isNew() || $page->isTrash() || $page->indexSaveFlag) return;

        $language = $this->wire("user")->language;    // save user lang
        $page->index = '';

        foreach($this->wire("languages") as $lang) {

            $this->wire("user")->language = $lang; // change user lang

            wire('pages')->setOutputFormatting(true);
            $content = $page->render(); // render page and get the content
            wire('pages')->setOutputFormatting(false);

            if($content) $content = $this->parseContent($content); //remove html, new lines etc...
            $page->index .= $content;
        }
    

        $page->indexSaveFlag = true; // in case it get's saved again (not case with Pages::saveReady)
        $this->wire("user")->language = $language; // restore user language
}

 

But when I try to save a page per api I get an Internal Server Error 500. When I replace "$page->render();" with "" inside the hook, it doesn't cause a internal server error anymore.

$page->save(); //causes internal server error now

 

Link to comment
Share on other sites

Maybe I don't fully understand what works and what doesn't in your case, but typically with hooks on after page save you can end up with recursion when you include $page->save inside the hook function. Typically you need to make it a "before" hook, or do: $page->save("index"); so that you are just saving the specific field (not the entire page), so that the hook won't be triggered again.

  • Like 1
Link to comment
Share on other sites

11 hours ago, Nukro said:

When I replace "$page->render();" with "" inside the hook, it doesn't cause a internal server error anymore.

This makes $content empty, so when you call parseContent() it is getting an empty string. Edit: actually, because of the if() test, parseContent() isn't called at all.

You don't show the parseContent() method in your code, and the problem could be there.

 

  • Like 1
Link to comment
Share on other sites

Thanks for your Input @adrian and @Robin S

I now changed the addHookAfter to addHookBefore. The indexing is still working. But the problem(internal server error) with saving from api when the hook is active is still consistent. The parseContent function contains some preg_replaces and strip_tags to clean out the html and define the "indexing area" so that the nav and footer content isn't indexed all the time.

parseContent()

protected function parseContent($content){
        $startStr = "<!--### start-indexing-area ###-->";
        $endStr = "<!--### end-indexing-area ###-->";

        preg_match_all('/'.$startStr.'(.*)'.$endStr.'/siU', $content, $matches);

        $newContent = preg_replace("/<div class='breadcrumb.*'>.*<\/div>/siU", '', $matches[1][0]);
        $newContent = str_replace('<', ' <', $newContent);
        $newContent = strip_tags($newContent);
        $newContent = preg_replace("/\s\s+/", " ", $newContent);
        return $newContent;
 }

It's really weird that it is causing a 500 internal server error when saving from api but it isn't causing a 500 internal server error when saving from backend, when the hookIndexingBefore is active.

Link to comment
Share on other sites

I think it has somehow something to do with the $page->render(). Because when I do this:

$content = <!--### start-indexing-area ###-->This is a sample Text<!--### end-indexing-area ###-->;

The Internal Server Error doesn't appear anymore. But when I save the $page->render() as $content I get the internal server error... It has also no effect when I do $page->render and skip the parseContent section, It still appears an internal server error. 

Link to comment
Share on other sites

I'm not sure what could be causing the 500 error. The Apache/PHP/PW error logs might shed some light. If this is happening on a live site then it could even be caused by mod_security - turn that off if you can or check with your host.

Rather than using your parseContent function you could consider rendering the page with a different template that is created with the index field in mind.

$page->render($filename); // $filename assumed in /site/templates/

See this post:

Or you could loop over the page's fields in the hook, checking for the type of each field and preparing it's value for the index field accordingly.

foreach($page->fields as $field) {
    /*
    you can get the value...
    $page->get($field->name);
    ...but you'll want to treat it differently based on field type
    if($field->type == 'FieldtypePage') {
        ...etc...
    }
    */
}

 

  • Like 3
Link to comment
Share on other sites

12 minutes ago, Robin S said:

I'm not sure what could be causing the 500 error. The Apache/PHP/PW error logs might shed some light. If this is happening on a live site then it could even be caused by mod_security - turn that off if you can or check with your host.

Rather than using your parseContent function you could consider rendering the page with a different template that is created with the index field in mind.


$page->render($filename); // $filename assumed in /site/templates/

See this post:

Or you could loop over the page's fields in the hook, checking for the type of each field and preparing it's value for the index field accordingly.


foreach($page->fields as $field) {
    /*
    you can get the value...
    $page->get($field->name);
    ...but you'll want to treat it differently based on field type
    if($field->type == 'FieldtypePage') {
        ...etc...
    }
    */
}

 

Thanks for your Input @Robin S!

I think I will go with the last option since it would solve another problem I have ;D.

Greetings Orkun

Link to comment
Share on other sites

Hi Guys

I had looked before inside all Apache/PHP/PW log files. There was nothing suspicous. But I have found something else that could be helpful.

I logged my hook so that I can watch what is happening. I have found out that my beforeHook on saveReady is called 4-5 times when I am saving from API and when the $content comes from $page->render(). When I save from API and the $content doesn't come from $page->render() it only calls 1 time like it should be. Does page->render calls saveReady function or something similar?

Link to comment
Share on other sites

I did a bit of a test. I'm using delayed output with an auto-appended "_main.php". I created a different append file "_main_index.php" for the purposes of rendering the index field: just echos the region variables without any HTML elements. Then in /site/ready.php...

$this->pages->addHookAfter('saveReady', function($event) {
    $page = $event->arguments('page');
    if($page->template->name !== 'basic_page') return;
    $page->index = $this->sanitizer->textarea($page->render(null, ['appendFile' => '_includes/_main_index.php']));
});

All works well, no errors or multiple calls to the hook when saving from the admin or the API. Maybe it's the fact that I'm hooking after saveReady that make the difference.

Edit: hooking before or after saveReady should make no difference. From the hook docs...

Quote

Some hookable methods in ProcessWire have no implementation and exist purely for you to hook. Because hooks like this exist purely "to be hooked", it doesn't matter if you hook before or after them. Examples include Pages::saveReady which is called after it's been determined the page will definitely be saved, but right before it is done.

 

Link to comment
Share on other sites

@Robin S

I have now made a file inside the root folder and bootstrapped PW in it. Now I don't get any internal server errors anymore. Some pages get saved now from the api until it stops, when the page is not viewable ( which is right ). But I have looked at this pages and they are visible to the guest user? I get errors like this: page "it/page-name" or "de/page-name" is not viewable etc... So i tought the languages are not activated in the page settings but they are all activated?

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...