Get html in plugin

How can I get the HTML for a route?

I am working on frontend editing plugin and want to preview a page (route) (or modular root route) in a <div>.

The quickest way is to set the src of an <iframe> to the full path, but modern servers now may prevent that because of cross site attacks.

I cannot find a function that is like

$html = $page->processAll()

which I can call in a plugin and have it sent by AJAX.

I don’t know the answer. I’ve never done something like this before. But be sure to check the API docs. The function processMarkdown() might do what you want.


I was looking at the GRAV hooks and found onOutputGenerated. It mentions that the output is now html. So how do I gain access to this string?

I have just submitted a new plugin content-edit to the GRAV team.

The aim is to offer frontend editing. With an <iframe> any route can be seen on some servers. I have tried processMarkdown(), but the plain vanilla function doesn’t return anything, eg., the html.

The API docs are not that complete or easy to understand unless you already understand them :frowning:

@finanalyst After some digging using the debugger, I found a variable ‘output’ in the object tree of ‘$this->grav’. This variable ‘output’ contains HTML. With some trial and error I finally found it can be accessed using:

$html = $this->grav['output'];

Somehow this output is already populated in ‘onPageInitialized’…

Very interesting. Thanks for the tip.

But like you said, there should not be any output in onPageInitialized. I wonder if this is the cached output.

@finanalyst When I edit the page in vscode and refresh the browser, ‘output’ contains the new HTML. So it probably isn’t from cache. Whether cache is enabled/disabled also does not make a difference.

I tried dumping $this->grav inside the plugin ‘onPageInitialised’, but …grav[‘output’] is null.

@finanalyst What do you mean by ‘dumping’?

When looking in the debugger the tree:

> $this
   > grav
      > output

shows indeed ‘null’. When digging deeper in the tree:

> $this
   > grav
      > *Pimple\Container*values
         > output

shows: <!DOCTYPE html>\n<html lang="en">\n<head>\n...

The following shows the entire ‘dump’ of $this->grav[‘output’] in the browser:

public function onPageInitialized()
    $html = $this->grav['output'];

Please don’t ask me how that early in the lifecycle of Grav the HTML is available…


Thank you for your help!!

I think I have solved the problem. Not quite the same as you have done (basically because I too don’t understand how the final html should be ready so early). Also, I want the html rendering of a route that is not the current route.

My version:

$html = $this->grav['twig']->processSite();
return $html;

Where $params['page'] contains the route of the page I want to preview in the <div> box, and it is not the route of the current route.

Whilst I appreciate it’s not your solution, without your help I would not have got this far.

NOT Solved! :((

The redirect sends the whole site with the new page, and exits. Thus the line after the redirect is not executed.

Since this code is generated by an AJAX call, the whole site gets put into a <div> and so interfers with the existing site code.

Still working on this.

@finanalyst Have discovered the same. The redirect jump out immediately.

I also wondered how you would display a page’s full HTML inside a <div> without collisions…

Back in the days when I used Joomla, they used an inline editor. A loggedin user get’s an extra ‘edit’ link in the page. On clicking it, an editor was injected.

So, instead of trying to inject the HTML of a page into the ‘editor’ page, the current page gets the editor injected.

That’s more-or-less what happens with another grav-plugin called editable-simplemde.

I’m trying to avoid that because of the problems with editing a modular page.

Currently, I’m trying (a) to cut off the bottom and top of the html, or use an iframe.

OK. Got it working.

Generate a redirect in response to an AJAX request, then feed that into an <iframe> with

success: {
  $('#iframe-container').attr('srcdoc', response);

This does not cause any browser errors.